| <HTML> |
| |
| <HEAD> |
| <TITLE>GRUB Technical Info</TITLE> |
| </HEAD> |
| |
| <BODY> |
| |
| <CENTER><H1>GRUB Technical Info</H1></CENTER> |
| <CENTER><H3>by |
| <A HREF=http://www.uruk.org/~erich/>Erich Boleyn</A></H3></CENTER> |
| |
| <HR> |
| |
| <H2>Contents</H2> |
| |
| <UL> |
| <LI> <A HREF="#challenges">Challenges/Issues</A> |
| <LI> <A HREF="#specs">Specifications and other Goals</A> |
| <LI> <A HREF="#features">Features</A> |
| <LI> <A HREF="#other">Other Implementation Details</A> |
| </UL> |
| |
| <HR> |
| |
| <H2><A NAME="challenges">Challenges/Issues</A></H2> |
| |
| Several major issues have plagued bootloaders for IBM PC compatibles for |
| a long time, mostly related to compatibility.<P> |
| |
| For more detail about the operation of standard floppy and hard disk |
| bootloaders, I have a 100K text document version of |
| <A HREF="PC_partitioning.txt">Hale Landis' How It Works Series</A>, |
| which is about the BIOS, booting, etc., and is very informative, though |
| mildly outdated, and with what seem to be a few errors. I'm looking into |
| getting updated information for flushing it out myself into a real |
| HTML document.<P> |
| |
| The worst problems and the general way they are solved in GRUB are |
| listed here (some of these have to be cooperatively solved with the OS):<P> |
| |
| <H3>Bootloader Size Limits</H3> |
| |
| Bootloaders have to be very small, typically limited to one or more very |
| small areas on the media in question.<P> |
| |
| At the start of the process, the BIOS loads the first block off of the |
| boot disk (floppy or hard drive), 512 bytes in size. This one block |
| must be capable of performing all the functions necessary to start up |
| the system, or handing off to another program. On a hard disk, at |
| least 64 bytes are reserved for a partition table, therefore unusable.<P> |
| |
| Traditionally, if the first block is not enough, at the start of the |
| partition with the OS being booted (or, for a floppy, just at the |
| beginning) is a fixed area, the size (generally from 512 bytes to |
| 8 Kbytes) of which is dependent on the filesystem variety in question.<P> |
| |
| Most bootloaders are written to fit within this limitation, giving them |
| only room for a very sparse functionality.<P> |
| |
| GRUB is very large compared to other bootloaders (typically |
| 20 to 30 K). A mechanism is |
| in place which can load all of it's components for different |
| <A HREF=install.html>installation methods</A>. |
| The feeling from |
| the author is that this will not be a problem since most of the features pay |
| for themselves both in terms of space (certainly the generic decompression |
| code, for example) and flexibilty |
| to both end-users and experts.<P> |
| |
| <H3>Partitioning Issues</H3> |
| |
| The traditional layout of a floppy on a PC is with the first block |
| being the boot-controller, and the rest of the disk being formatted |
| to some filesystem type.<P> |
| |
| The traditional layout of a hard disk on a PC is with the first block |
| being the boot-controller, referred to as the MBR (Master Boot Record), |
| with the rest of the disk subdivided into 4 sections (called |
| "partitions"), each of which look either like a logical floppy |
| (boot block + filsystem), or a full hard disk (sort of a recursive |
| definition here, though only one of the partitions can be one of |
| these). Inside one of the recursive hard disk definitions, only one |
| of the 4 partitions can have a filesystem. The pratical result is that |
| an arbitrary number of partitions can be represented. The biggest |
| problem here is that generally only one of the 4 partitions listed |
| directly in the main MBR can be the "active" one, which is the one |
| where any subsidary boot blocks are pulled from.<P> |
| |
| Most bootloaders don't deal with the "active partition" marker in |
| a very intelligent manner.<P> |
| |
| GRUB can both PC style partitions (normal and extended DOS-style) and |
| 386BSD/Mach style BSD sub-partitions in a consistent manner, plus it |
| can set the "active partition" marker as desired (he "active partition" |
| marker is currently irrelevant to GRUBs actual behavior, this still |
| needs some work related to default device notations).<P> |
| |
| <H3>Geometry Translation</H3> |
| |
| There are several methods of using the BIOS to access a disk before |
| any kind of driver is active. The only consistent one is the INT 13h |
| interface, which uses an addressing scheme based on the Cylinder, Head, |
| and Sector positions of a block, packed into a value consisting of 10 bits, |
| 8 bits, and 6 bits, respectively.<P> |
| |
| To attempt to get around this issue, and in the case of SCSI disks, to allow |
| a differential number of sectors in different physical cylinders without |
| confusing the heck out of the software, the concept of Geometry Translation |
| was introduced. Geometry Translation produces a transparent virtual |
| mapping from some phantom number of Cylinders, Sectors and Heads onto |
| the real hardware of the disk, generally trying to increase the space of |
| the disk accessible via the INT 13h interface.<P> |
| |
| Another problem created from the above is that different controller/BIOS |
| combinations (and possibly even different particular installations of |
| software) can use different geometry translations, and since the bootloaders |
| on the disk depend on the particular numbers, they either have to be |
| carefully updated, or, in some cases, the whole OS must be re-installed when |
| moving the disk to another controller/BIOS combination.<P> |
| |
| The essential issue is that pretty much all bootloaders prior to GRUB use |
| Cylinder/Head/Sector numbers for the first stage of booting, so if |
| that mapping should change, your OS can't boot, even though the linear |
| mapping is the same, and if you could get it booted somehow, everything |
| work would fine.<P> |
| |
| GRUB solves this by translating from/to a linear block-number |
| <B>AT ALL TIMES</B>. This turns out to be OK, as the major OS used |
| to test a BIOS translation mechanism, DOS, uses exactly the same |
| mappings.<P> |
| |
| <H3>512MB - 8GB BIOS Translation Size Limits</H3> |
| |
| Related to the Gemetry Translation problem is the problem that in standard |
| INT 13h BIOS interface has a maximum of 24 bits to access the disk with.<P> |
| |
| The problem is that even |
| presuming a perfectly spanned space, 24 bits is only 16 M blocks, |
| and at 512 bytes each, |
| this is a maximum disk size of 8 GB. Most real systems have limitations |
| of either 512 MB (this is where the IDE limit of 508 MB comes from, I'm |
| pretty sure, as the top 4 bits of the "head" number can't be used |
| in most BIOS IDE interfaces), or 1 GB, though this is changing, moving |
| toward the 8 GB maximum size.<P> |
| |
| GRUB can't universally solve this problem, as there is no new interface |
| which is used in all machines. At least one newer interface which |
| is present on some machines ("LBA", which is in more and more new |
| ones, supposedly) may |
| be able to be used transparently in place of INT 13h when available. |
| This is still being investigated.<P> |
| |
| <H3>Memory size determination</H3> |
| |
| Various OS's do this differently. Some rely on their bootloader, and |
| some perform the probe themselves. Most are limited to detecting a |
| maximum of 64MB on a PC, in any case. Kludges where a hard-coded |
| portion telling the machine how much RAM is installed, or even compiling |
| it in, have been made for many OSes.<P> |
| |
| Since this is both once-only |
| code and only involves the BIOS, the solution which Multiboot and |
| GRUB uses is to perform the probe in the bootloader. |
| Look at the bulleted item "Detects all Installed RAM" in the section |
| <A HREF="#features">Features</A> below.<P> |
| |
| <HR> |
| |
| <H2><A NAME="specs">Specifications and other Goals</A></H2> |
| |
| The primary requirement for GRUB is that it be compliant with the |
| <A HREF="boot-proposal.html">Multiboot Standard</A>.<P> |
| |
| The other goals, listed in approximate order of importance, are:<P> |
| |
| <UL> |
| <LI>Basic functions must be easy for an end-user to use.<P> |
| <LI>Rich functionality for OS experts/designers.<P> |
| <LI>Compatibility for booting FreeBSD, NetBSD, and Linux. |
| Proprietary OS's such as DOS, Windows NT, and OS/2 are |
| supported via a chain-loading function.<P> |
| </UL> |
| |
| Except for specific compatibility modes (chain-loading and the |
| Linux 'piggyback' format), |
| all kernels will be started in much the same state as in the Multiboot |
| Standard listed above. Only kernels being loaded at 1 megabyte or above |
| are presently supported. Any attempt to load below that boundary will |
| simply result in immediate failure and an error message reporting the |
| problem.<P> |
| |
| <HR> |
| |
| <H2><A NAME="features">Features</A></H2> |
| |
| In addition to the requirements in the previous section, GRUB has the |
| following features (note that the Multiboot Standard doesn't explicitly |
| require everything listed in it, but GRUB will support all options):<P> |
| |
| <UL> |
| <LI><B>Multiple Executable Formats</B>: Supports many of the <B>a.out</B> |
| variants plus <B>ELF</B>. Any symbol table present is also loaded.<P> |
| <LI><B>Supports Non-Multiboot OS's</B>: Supports many of the various |
| free 32-bit OS's prior to any Multiboot compliance. Chiefly FreeBSD, |
| NetBSD, and Linux. Chain-loading is also supported.<P> |
| <LI><B>Loads Multiple Modules</B>: Multiboot feature of loading multiple |
| modules is fully supported.<P> |
| <LI><B>Configuration File</B>: |
| Supports a human-readable text configuration file with preset boot commands. |
| The <A HREF=commands.txt>list of commands</A> are a superset |
| of those supported on the command-line. |
| An <A HREF=menu.lst>example command-file</A> is provided.<P> |
| <LI><B>Menu Interface</B>: A menu-interface listing |
| the preset boot commands, with a programmable timeout, is available. |
| There is no fixed limit on the number of boot command-set entries, and |
| should have space for several hundred.<P> |
| <LI><B>Flexible Command-Line Interface</B>: A fairly flexible |
| command-line interface, accessible from the |
| menu, is available to edit any preset commands, or simply start a new |
| command-set from scratch. |
| The <A HREF=commands.txt>list of commands</A> are a subset of those |
| supported for command-files. Editing commands closely resemble the |
| BASH shell command-line, with TAB-completion-listing (it doesn't |
| perform the completion, just lists the possibilities) of commands, |
| devices, partitions, and files in a directory depending on context. |
| If no config file is present, it goes into the command-line.<P> |
| <LI><B>Multiple Filesystem Types</B>: Supports multiple filesystem |
| types transparently, plus an explicitly usable block-list notation. |
| The currently supported filesystem types are <B>BSD FFS</B>, <B>DOS FAT</B>, |
| and <B>Linux ext2fs</B>. There is also a page describing the |
| <A HREF=filesystem.txt>GRUB filesystems and interfaces</A>.<P> |
| <LI><B>Decompression Support</B>: Can decompress files which were |
| compressed with using "gzip". This function is both automatic and |
| transparent to the user (i.e. all functions operate normally upon |
| the uncompressed contents of the files in question). This is a win |
| on 2 fronts, as it both greatly reduces file size and loading time (there |
| are a few pathological cases where loading a very badly organized ELF |
| kernel might make it take longer, but IMO you'll never see this in |
| practice), a particularly major win for floppies. It is conceivable |
| that some kernel modules should be loaded in a compressed state, so a |
| variant of the module loading command which doesn't uncompress them |
| can be used.<P> |
| <LI><B>Access Data on Any Installed Device</B>: Supports reading data |
| from any or all floppy or hard disk(s) recognized by the BIOS, independent |
| of the setting for the root partition.<P> |
| <LI><B>Geometry Translation-Idependent</B>: Subject to the constraint |
| that it cannot go past the end of the geometry-translated area of a drive, |
| the particular translation used is generally irrelevant. This implies a |
| drive installed and running on a controller with one translation in use |
| may in general be moved to another controller with a different translation |
| (or the translation settings on the first controller, if configurable, |
| may be changed) with no adverse effects and no other changes necessary.<P> |
| <LI><B>Detects All Installed RAM</B>: GRUB can generally find all the |
| installed RAM on a PC-compatible machine. It uses the |
| BIOS query technique described on the |
| <A HREF="mem64mb.html"> |
| INT 15h, AX=E820h - Query System Address Map</A> web page. As described on |
| the Multiboot Standard web page listed above, OS's which only use the |
| lower and upper memory values (whose presence is determined by bit 0 of |
| the flags word passed to the OS) may not be capable of receiving information |
| on all of installed memory. On most machines, upper memory is contiguous, |
| so the problem does not arise.<P> |
| </UL> |
| |
| Future directions might include an internal programming language for |
| supporting richer sets of boot options with control statements |
| (it becomes a boot-script at that point), |
| and possibly support for non-IBM PC-compatible machines.<P> |
| |
| One definite path for future work is how to fairly transparently get |
| around the 8 GB geometry translation limitation.<P> |
| |
| <HR> |
| |
| <H2><A NAME="other">Other Implementation Details</A></H2> |
| |
| GRUB can completely replace the primary bootloader on a hard disk or |
| floppy disk. On a hard disk, it can also be run after some other |
| bootloader capable of chain-loading.<P> |
| |
| GRUB is broken into 2 distinct components, or stages, which are loaded at |
| different times in the boot process. The Stage 1 has to know where to |
| find Stage 2, and the Stage 2 has to know where to find it's configuration |
| file (if Stage 2 doesn't have a config file, it drops into the command-line |
| interface and waits for a user command).<P> |
| |
| Here is a memory map of the various components:<P> |
| |
| <pre> |
| |
| 0 to 4K-1 : Interrupt & BIOS area. |
| |
| down from 8K-1 : 16-bit stack area. |
| |
| 8K to (ebss1.5) : Stage-1.5 (optionally) loaded here by Stage-1. |
| |
| 0x7c00 to 0x7dff : Stage-1 loaded here by the BIOS. |
| 0x7e00 to 0x7e08 : scratch space used by Stage-1. |
| |
| 32K to (ebss2) : Stage-2 loaded here by Stage-1.5 or Stage-1. |
| |
| (middle area) : heap used for random memory allocation. |
| |
| down from 416K-1 : 32-bit stack area. |
| |
| 416K to 448K-1 : Filesystem info buffer (when reading a filesys). |
| 448K to 479.5K-1 : BIOS track read buffer. |
| 479.5K to 480K-1 : 512 byte fixed SCRATCH area. |
| |
| 480K to 511K-1 : general storage heap. |
| |
| </pre> |
| |
| Description of GRUB's major components (and some of the boot sequence):<P> |
| |
| <H3>Stage 1</H3> |
| |
| Stage 1 is only used to load Stage 2. If Stage 2 can be loaded in |
| some other manner in a compatible fashion, then Stage 1 is unnecessary, |
| and doesn't need to be used.<P> |
| |
| <UL> |
| <LI>On a floppy, there is generally only one possible boot area, the first |
| boot sector. The Stage 1 portion would go there.<P> |
| <LI>On a hard disk, Stage 1 can be part of the MBR block or part of the |
| first block of some partition.<P> |
| </UL> |
| |
| Stage 1 "knows" where Stage 2 is by entries in a block-list loading table |
| embedded in it. It loads the lists of blocks off of the booting drive, |
| then jumps to a specified CS:IP in 16-bit real mode. These are described |
| in the page on <A HREF=embedded_data.txt>embedded data</A>. It queries the |
| BIOS for the disk geometry, and maps the linear block numbers there to |
| C:H:S addresses used by the INT 13h BIOS interface.<P> |
| |
| See the <A HREF=install.html>Installation |
| Guide</A> for details on how to set up loading Stage 2 from Stage 1.<P> |
| |
| <H3>OPTIONAL Stage 1.5</H3> |
| |
| Since the Stage 2 is so large (typically 30K or larger in size), |
| a special stripped down version of the |
| Stage 2 code, sort of a Stage 1.5, can be used because it might fit into |
| one of the fixed areas of the disk. The idea is to have the Stage 1.5 |
| look for a certain file and attempt to execute it as a Stage 2 (this |
| allows changing Stage 2 easily, while leaving it a normal file in |
| the filesystem).<P> |
| |
| This is actually the case for the BSD FFS filesystem. There is a fixed |
| area 7K in size at the beginning of the partition which is reserved for |
| the bootloader. The Stage 1.5 with BSD FFS filesystem support is |
| about 6.5 K in size when compiled in a.out format, and fits nicely, |
| allowing the Stage 2 to be a normal file in the "/boot/grub" directory |
| of the install partition.<P> |
| |
| This same technique can in principle be applied to other filesystems, |
| but the problem here is that the fixed area available to bootloaders is |
| generally quite small (0.5 to 3 K), and a Stage 1.5 wouldn't fit.<P> |
| |
| It contains |
| <A HREF=embedded_data.txt>embedded data</A> |
| on where to look for the install partition |
| and the Stage 2 (it uses what would be the "configuration file" |
| entry in the Stage 2 for this purpose).<P> |
| |
| <H3>Stage 2</H3> |
| |
| This component is the GRUB proper.<P> |
| |
| It gets most of the information about the machine and the boot state |
| from the BIOS and information passed into it at starting time, except |
| that it contains |
| <A HREF=embedded_data.txt>embedded data</A> |
| on where to look for the install partition and the configuration file.<P> |
| |
| The first action of the Stage 2 is to look for it's configuration file. |
| If one is not found, then |
| it drops into the command-line interface. |
| If one is found, the full menu interface is activated containing |
| whatever entries were found in the file (the command-line is still |
| available via a command from the menu interface).<P> |
| |
| <HR> |
| |
| <A HREF=mailto:erich@uruk.org><I>erich@uruk.org</I></A><P> |
| |
| </BODY> |
| </HTML> |