mirror of
https://git.savannah.gnu.org/git/grub.git
synced 2026-10-22 07:12:39 +00:00
The new grub manual is made official.
This commit is contained in:
1 parent
cf58c5c2a9
commit
d20f9609ce
12 files changed
+4009
-8517
No files matched your search
@@ -0,0 +1,427 @@
|
||||
@node Internals
|
||||
@chapter Hacking GRUB
|
||||
|
||||
This chapter documents the user-invisible aspect of GRUB.
|
||||
|
||||
As a general rule of software development, it is impossible to keep the
|
||||
descriptions of the internals up-to-date, and it is quite hard to
|
||||
document everything. So refer to the source code, whenever you are not
|
||||
satisfied with this documentation. Please assume that this gives just
|
||||
hints to you.
|
||||
|
||||
@menu
|
||||
* Memory map:: The memory map of various components
|
||||
* Embedded data:: Embedded variables in GRUB
|
||||
* Filesystem interface:: The generic interface for filesystems
|
||||
* Command interface:: The generic interface for built-ins
|
||||
* Bootstrap tricks:: The bootstrap mechanism used in GRUB
|
||||
* I/O ports detection:: How to probe I/O ports used by INT 13H
|
||||
* Memory detection:: How to detect all installed RAM
|
||||
* Low-level disk I/O:: INT 13H disk I/O interrupts
|
||||
* MBR:: The structure of Master Boot Record
|
||||
* Partition table:: The format of partition tables
|
||||
* Submitting patches:: Where and how you should send patches
|
||||
@end menu
|
||||
|
||||
|
||||
@node Memory map
|
||||
@section The memory map of various components
|
||||
|
||||
GRUB consists of two distinct components, called @dfn{stages}, which are
|
||||
loaded at different times in the boot process. Because they run
|
||||
mutual-exclusively, sometimes a memory area overlaps with another
|
||||
memory area. And, even in one stage, a single memory area can be used
|
||||
for various purposes, because their usages are mutually exclusive.
|
||||
|
||||
Here is the memory map of the various components:
|
||||
|
||||
@table @asis
|
||||
@item 0 to 4K-1
|
||||
BIOS and real mode interrupts
|
||||
|
||||
@item 0x07BE to 0x07FF
|
||||
Partition table passed to another boot loader
|
||||
|
||||
@item down from 8K-1
|
||||
Real mode stack
|
||||
|
||||
@item 0x2000 to ?
|
||||
The optional Stage 1.5 is loaded here
|
||||
|
||||
@item 0x2000 to 0x7FFF
|
||||
Command-line buffer for Multiboot kernels and modules
|
||||
|
||||
@item 0x7C00 to 0x7DFF
|
||||
Stage 1 is loaded here by BIOS or another boot loader
|
||||
|
||||
@item 0x7F00 to 0x7F42
|
||||
LBA drive parameters
|
||||
|
||||
@item 0x8000 to ?
|
||||
Stage2 is loaded here
|
||||
|
||||
@item The end of Stage 2 to 416K-1
|
||||
Heap, in particular used for the menu
|
||||
|
||||
@item down from 416K-1
|
||||
Protected mode stack
|
||||
|
||||
@item 416K to 448K-1
|
||||
Filesystem buffer
|
||||
|
||||
@item 448K to 479.5K-1
|
||||
Raw device buffer
|
||||
|
||||
@item 479.5K to 480K-1
|
||||
512-byte scratch area
|
||||
|
||||
@item 480K to 512K-1
|
||||
Buffers for various functions, such as password, command-line, cut and
|
||||
paste, and completion.
|
||||
|
||||
@item The last 1K of lower memory
|
||||
Disk swapping code and data
|
||||
@end table
|
||||
|
||||
See the file @file{stage2/shared.h}, for more information.
|
||||
|
||||
|
||||
@node Embedded data
|
||||
@section Embedded variables in GRUB
|
||||
|
||||
Stage 1 and Stage 2 have embedded variables whose locations are
|
||||
well-defined, so that the installation can patch the binary file
|
||||
directly without recompilation of the stages.
|
||||
|
||||
In Stage 1, these are defined:
|
||||
|
||||
@table @code
|
||||
@item 0x3E
|
||||
The version number (not GRUB's, but the installation mechanism's).
|
||||
|
||||
@item 0x40
|
||||
The boot drive. If it is 0xFF, use a drive passed by BIOS.
|
||||
|
||||
@item 0x41
|
||||
The flag for if forcing LBA.
|
||||
|
||||
@item 0x42
|
||||
The starting address of Stage 2.
|
||||
|
||||
@item 0x44
|
||||
The first sector of Stage 2.
|
||||
|
||||
@item 0x48
|
||||
The starting segment of Stage 2.
|
||||
|
||||
@item 0x1FE
|
||||
The signature (@code{0xAA55}).
|
||||
@end table
|
||||
|
||||
See the file @file{stage1/stage1.S}, for more information.
|
||||
|
||||
In the first sector of Stage 1.5 and Stage 2, the block lists are
|
||||
recorded between @code{firstlist} and @code{lastlist}. The address of
|
||||
@code{lastlist} is determined when assembling the file
|
||||
@file{stage2/start.S}.
|
||||
|
||||
The trick here is that it is actually read backward, and the first
|
||||
8-byte block list is not read here, but after the pointer is decremented
|
||||
8 bytes, then after reading it, it decrements again, reads, and so on,
|
||||
until it is finished. The terminating condition is when the number of
|
||||
sectors to be read in the next block list is zero.
|
||||
|
||||
The format of a block list can be seen from the example in the code just
|
||||
before the @code{firstlist} label. Note that it is always from the
|
||||
beginning of the disk, but @emph{not} relative to the partition
|
||||
boundaries.
|
||||
|
||||
In the second sector of Stage 1.5 and Stage 2, these are defined:
|
||||
|
||||
@table @asis
|
||||
@item @code{0x6}
|
||||
The version number (likewise, the installation mechanism's).
|
||||
|
||||
@item @code{0x8}
|
||||
The installed partition.
|
||||
|
||||
@item @code{0xC}
|
||||
The saved entry number.
|
||||
|
||||
@item @code{0x10}
|
||||
The identifier.
|
||||
|
||||
@item @code{0x11}
|
||||
The flag for if forcing LBA.
|
||||
|
||||
@item @code{0x12}
|
||||
The version string (GRUB's).
|
||||
|
||||
@item @code{0x12} + @dfn{the length of the version string}
|
||||
The name of a configuration file.
|
||||
@end table
|
||||
|
||||
See the file @file{stage2/asm.S}, for more information.
|
||||
|
||||
|
||||
@node Filesystem interface
|
||||
@section The generic interface for filesystems
|
||||
|
||||
For any particular partition, it is presumed that only one of the
|
||||
@dfn{normal} filesystems such as FAT, FFS, or ext2fs can be used, so
|
||||
there is a switch table managed by the functions in
|
||||
@file{disk_io.c}. The notation is that you can only @dfn{mount} one at a
|
||||
time.
|
||||
|
||||
The block list filesystem has a special place in the system. In addition
|
||||
to the @dfn{normal} filesystem (or even without one mounted), you can
|
||||
access disk blocks directly (in the indicated partition) via the block
|
||||
list notation. Using the block list filesystem doesn't effect any other
|
||||
filesystem mounts.
|
||||
|
||||
The variables which can be read by the filesystem backend are:
|
||||
|
||||
@vtable @code
|
||||
@item current_drive
|
||||
The current BIOS drive number (numbered from 0, if a floppy, and
|
||||
numbered from 0x80, if a hard disk).
|
||||
|
||||
@item current_partition
|
||||
The current partition number.
|
||||
|
||||
@item current_slice
|
||||
The current partition type.
|
||||
|
||||
@item saved_drive
|
||||
The @dfn{drive} part of the root device.
|
||||
|
||||
@item saved_partition
|
||||
The @dfn{partition} part of the root device.
|
||||
|
||||
@item part_start
|
||||
The current partition starting address, in sectors.
|
||||
|
||||
@item part_length
|
||||
The current partition length, in sectors.
|
||||
|
||||
@item print_possibilities
|
||||
True when the @code{dir} function should print the possible completions
|
||||
of a file, and false when it should try to actually open a file of that
|
||||
name.
|
||||
|
||||
@item FSYS_BUF
|
||||
Filesystem buffer which is 32K in size, to use in any way which the
|
||||
filesystem backend desires.
|
||||
@end vtable
|
||||
|
||||
The variables which need to be written by a filesystem backend are:
|
||||
|
||||
@vtable @code
|
||||
@item filepos
|
||||
The current position in the file, in sectors.
|
||||
|
||||
@strong{Caution:} the value of @var{filepos} can be changed out from
|
||||
under the filesystem code in the current implementation. Don't depend on
|
||||
it being the same for later calls into the backend code!
|
||||
|
||||
@item filemax
|
||||
The length of the file.
|
||||
|
||||
@item disk_read_func
|
||||
The value of @var{disk_read_hook} @emph{only} during reading of data
|
||||
for the file, not any other fs data, inodes, FAT tables, whatever, then
|
||||
set to @code{NULL} at all other times (it will be @code{NULL} by
|
||||
default). If this isn't done correctly, then the @command{testload} and
|
||||
@command{install} commands won't work correctly.
|
||||
@end vtable
|
||||
|
||||
The functions expected to be used by the filesystem backend are:
|
||||
|
||||
@ftable @code
|
||||
@item devread
|
||||
Only read sectors from within a partition. Sector 0 is the first sector
|
||||
in the partition.
|
||||
|
||||
@item grub_read
|
||||
If the backend uses the block list code, then @code{grub_read} can be
|
||||
used, after setting @var{block_file} to 1.
|
||||
|
||||
@item print_a_completion
|
||||
If @var{print_possibilities} is true, call @code{print_a_completion} for
|
||||
each possible file name. Otherwise, the file name completion won't work.
|
||||
@end ftable
|
||||
|
||||
The functions expected to be defined by the filesystem backend are
|
||||
described at least moderately in the file @file{filesys.h}. Their usage
|
||||
is fairly evident from their use in the functions in @file{disk_io.c},
|
||||
look for the use of the @var{fsys_table} array.
|
||||
|
||||
@strong{Caution:} The semantics are such that then @samp{mount}ing the
|
||||
filesystem, presume the filesystem buffer @code{FSYS_BUF} is corrupted,
|
||||
and (re-)load all important contents. When opening and reading a file,
|
||||
presume that the data from the @samp{mount} is available, and doesn't
|
||||
get corrupted by the open/read (i.e. multiple opens and/or reads will be
|
||||
done with only one mount if in the same filesystem).
|
||||
|
||||
|
||||
@node Command interface
|
||||
@section The generic interface for built-ins
|
||||
|
||||
GRUB built-in commands are defined in a uniformal interface, whether
|
||||
they are menu-specific or can be used anywhere. The definition of a
|
||||
builtin command consists of two parts: the code itself and the table of
|
||||
the information.
|
||||
|
||||
The code must be a function which takes two arguments, a command-line
|
||||
string and flags, and returns an @samp{int} value. The @dfn{flags}
|
||||
argument specifies how the function is called, using a bit mask. The
|
||||
return value must be zero if successful, otherwise non-zero. So it is
|
||||
normally enough to return @var{errnum}.
|
||||
|
||||
The table of the information is represented by the structure
|
||||
@code{struct builtin}, which contains the name of the command, a pointer
|
||||
to the function, flags, a short description of the command and a long
|
||||
description of the command. Since the descriptions are used only for
|
||||
help messages interactively, you don't have to define them, if the
|
||||
command may not be called interactively (such as @command{title}).
|
||||
|
||||
The table is finally registered in the table @var{builtin_table}, so
|
||||
that @code{run_script} and @code{enter_cmdline} can find the
|
||||
command. See the files @file{cmdline.c} and @file{builtins.c}, for more
|
||||
details.
|
||||
|
||||
|
||||
@node Bootstrap tricks
|
||||
@section The bootstrap mechanism used in GRUB
|
||||
|
||||
The disk space can be used in a boot loader is very restricted because
|
||||
a MBR (@pxref{MBR}) is only 512 bytes but it also contains a partition
|
||||
table (@pxref{Partition table}) and a BPB. So the question is how to
|
||||
make a boot loader code enough small to be fit in a MBR.
|
||||
|
||||
However, GRUB is a very large program, so we break GRUB into 2 (or 3)
|
||||
distinct components, @dfn{Stage 1} and @dfn{Stage 2} (and optionally
|
||||
@dfn{Stage 1.5}). @xref{Memory map}, for more information.
|
||||
|
||||
We embed Stage 1 in a MBR or in the boot sector of a partition, and
|
||||
place Stage 2 in a filesystem. The optional Stage 1.5 can be installed
|
||||
in a filesystem, in the @dfn{boot loader} area in a FFS or a ReiserFS,
|
||||
and in the sectors right after a MBR, because Stage 1.5 is enough small
|
||||
and the sectors right after a MBR is normally an unused region. The size
|
||||
of this region is the number of sectors per head minus 1.
|
||||
|
||||
Thus, all Stage1 must do is just load Stage2 or Stage1.5. But even if
|
||||
Stage 1 needs not to support the user interface or the filesystem
|
||||
interface, it is impossible to make Stage 1 less than 400 bytes, because
|
||||
GRUB should support both the CHS mode and the LBA mode (@pxref{Low-level
|
||||
disk I/O}).
|
||||
|
||||
The solution used by GRUB is that Stage 1 loads only the first sector of
|
||||
Stage 2 (or Stage 1.5) and Stage 2 itself loads the rest. The flow of
|
||||
Stage 1 is:
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Initialize the system briefly.
|
||||
|
||||
@item
|
||||
Detect the geometry and the accessing mode of the @dfn{loading drive}.
|
||||
|
||||
@item
|
||||
Load the first sector of Stage 2.
|
||||
|
||||
@item
|
||||
Jump to the starting address of the Stage 2.
|
||||
@end enumerate
|
||||
|
||||
The flow of Stage 2 (and Stage 1.5) is:
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Load the rest of itself to the real starting address, that is, the
|
||||
starting address plus 512 bytes. The block lists are stored in the last
|
||||
part of the first sector.
|
||||
|
||||
@item
|
||||
Long jump to the real starting address.
|
||||
@end enumerate
|
||||
|
||||
Note that Stage 2 (or Stage 1.5) does not probe the geometry
|
||||
or the accessing mode of the @dfn{loading drive}, since Stage 1 has
|
||||
already probed them.
|
||||
|
||||
|
||||
@node I/O ports detection
|
||||
@section How to probe I/O ports used by INT 13H
|
||||
|
||||
FIXME: I will write this chapter after implementing the new technique.
|
||||
|
||||
|
||||
|
||||
@node Memory detection
|
||||
@section How to detect all installed RAM
|
||||
|
||||
FIXME: I doubt if Erich didn't write this chapter only himself wholly,
|
||||
so I will rewrite this chapter.
|
||||
|
||||
|
||||
@node Low-level disk I/O
|
||||
@section INT 13H disk I/O interrupts
|
||||
|
||||
FIXME: I'm not sure where some part of the original chapter is derived,
|
||||
so I will rewrite this chapter.
|
||||
|
||||
|
||||
@node MBR
|
||||
@section The structure of Master Boot Record
|
||||
|
||||
FIXME: Likewise.
|
||||
|
||||
|
||||
@node Partition table
|
||||
@section The format of partition tables
|
||||
|
||||
FIXME: Probably the original chapter is derived from "How It Works", so
|
||||
I will rewrite this chapter.
|
||||
|
||||
|
||||
@node Submitting patches
|
||||
@section Where and how you should send patches
|
||||
|
||||
When you write patches for GRUB, please send them to the mailing list
|
||||
@email{bug-grub@@gnu.org}. Here is the list of items of which you
|
||||
should take care:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Please make your patch as small as possible. Generally, it is not a good
|
||||
thing to make one big patch which changes many things. Instead,
|
||||
segregate features and produce many patches.
|
||||
|
||||
@item
|
||||
Use as late code as possible, for the original code. The CVS repository
|
||||
always has the current version (@pxref{Obtaining and Building GRUB}).
|
||||
|
||||
@item
|
||||
Write ChangeLog entries. @xref{Change Logs, , Change Logs, standards,
|
||||
GNU Coding Standards}, if you don't know how to write ChangeLog.
|
||||
|
||||
@item
|
||||
Make patches in unified diff format. @samp{diff -urN} is appropriate in
|
||||
most cases.
|
||||
|
||||
@item
|
||||
Don't make patches reversely. Reverse patches are difficult to read and
|
||||
use.
|
||||
|
||||
@item
|
||||
Be careful enough of the license term and the copyright. Because GRUB
|
||||
is under GNU General Public License, you may not steal code from
|
||||
software whose license is incompatible against GPL. And, if you copy
|
||||
code written by others, you must not ignore their copyrights. Feel free
|
||||
to ask GRUB maintainers, whenever you are not sure what you should do.
|
||||
|
||||
@item
|
||||
If your patch is too large to send in e-mail, put it at somewhere we can
|
||||
see. Usually, you shouldn't send e-mail over 20K.
|
||||
@end itemize
|
||||
Reference in new issue
Block a user