GRUB master boot record



Like the Boot Records of an OS, the first three bytes could be called
the Jump Instruction. But only the first two bytes are being used to
form the actual JMP (Jump) instruction to the rest of the executable
code; the third byte (90h) is just a NOP instruction ('No Op' do
nothing). So the execution jumps over the 71 next bytes which can be
thought of as a BIOS Parameter Block (or BPB);
BIOS parameter block (BPB) is a description of the physical medium
(hard disk or floppy) that might be stored in a file system’s Volume
Boot Record. File systems with a BIOS parameter block include FAT16,
FAT32, HPFS, and NTFS. ECMA-107 or ISO/IEC 9293 (which describes FAT
as for flexible/floppy and optic distal disk cartridges) also
describes this as an FDC Descriptor or an FDC Extended Descriptor.


00000000 EB48 jmp short 0x4a
00000002 90 nop
Jump to the start of the program at 0x7c00 and is jumped to with CS:IP
0:0x7c00.
Jump over BPB data area to main body of code.
This BPB Data Area (BIOS Parameter Block) is filled with useful data
for any program examining it as a normal Volume Boot Record.

The BYTES in the BPB which are referenced in the code below are:

[00000005] -> 8E D0 BC 00 B0 B8 00 00 8E D8 8E C0 FB BE
("Disk Address Packet" for LBA mode.)

[00000040] -> 80 ("Boot Drive") NOTE: For those of you with multi-
OS
booting systems, if your Linux installation with GRUB's
remaining software (stage2, menu file, etc.) is located
somewhere other than on the Primary Master drive, this
value will be 81, 82, etc. depending upon which drive
that Linux OS's /boot/grub directory is located.

[00000041] -> 00 ("Force LBA mode byte")
[00000042] -> 00 80 (8000h) Memory location where GRUB stores the
next stage of the code to execute.
[00000044] -> Note: A very important location for anyone using
GRUB!
This (4-byte) Quad-Word contains the location of GRUB's
stage2 file in sectors! You will always see the bytes
01 00 00 00 in this location whenever GRUB has been
installed in the first track (Sectors 1 ff.) of an HDD;
immediately following the GRUB MBR in Absolute Sector 0.

[00000048] -> 00 08 (800h) [Don't confuse this with the 8000 at
00000042.]

00000003 10
00000004 8E
00000005 D0
00000006 BC
00000007 00
00000008 B0
00000009 B8
0000000A 00
0000000B 00
0000000C 8E
0000000D D8
0000000E 8E
0000000F C0
00000010 FB
00000011 BE
00000012 00
00000013 7C
00000014 BF
00000015 00
00000016 06
00000017 B9
00000018 00
00000019 02
0000001A F3
0000001B A4
0000001C EA
0000001D 21
0000001E 06
0000001F 00
00000020 00
00000021 BE
00000022 BE
00000023 07
00000024 38
00000025 04
00000026 75
00000027 0B
00000028 83
00000029 C6
0000002A 10
0000002B 81
0000002C FE
0000002D FE
0000002E 07
0000002F 75
00000030 F3
00000031 EB
00000032 16
00000033 B4
00000034 02
00000035 B0
00000036 01
00000037 BB
00000038 00
00000039 7C
0000003A B2
0000003B 80
0000003C 8A
0000003D 74
0000003E 03
0000003F 02
00000040 80
00000041 00
00000042 00
00000043 80
00000044 8B
00000045 82
00000046 00
00000047 00
00000048 00
00000049 08


General setup:

0000004A FA cli
This line will Clear Interrupt Flag
This is a workaround for buggy BIOSes which don't pass boot drive
correctly. If GRUB is installed into a HDD, check if DL is masked
correctly. If not, assume that the BIOS passed a bogus value and set
DL to 0x80, since this is the only possible boot drive. If GRUB is
installed into a floppy, this does nothing (only jump).

0000004B EA507C0000 jmp 0x0:0x7c50
Long Jump to the next instruction because some bogus BIOSes jump to
07C0:0000 instead of 0000:7C00.

00000050 31C0 xor ax,ax
00000052 8ED8 mov ds,ax
00000054 8ED0 mov ss,ax
set up %ds and %ss as offset from 0

00000056 BC0020 mov sp,0x2000
set up the REAL stack

00000059 FB sti
Set Interrupt Flag
This instruction sets the interrupt flag (IF) in the EFLAGS register.
After the IF flag is set, the processor begins responding to external,
mask able interrupts after the next instruction is executed.

0000005A A0407C mov al,[0x7c40] <<<<<<<< Boot Drive
Check if we have a forced disk reference here

0000005D 3CFF cmp al,0xff
Compare GRUB_INVALID_DRIVE and al

0000005F 7402 jz 0x63

jump to the next instruction because some bogus BIOSes jump to
07C0:0000 instead of 0000:7C00.

00000061 88C2 mov dl,al

00000063 52 push dx
Save drive reference first thing!

00000064 BE767D mov si,0x7d76
00000067 E83401 call 0x19e
Print a notification message on the screen.
The first line “0x7d76” is the place of the string “GRUB” on memory.
“0x19e” is the place of the function that print the message on screen
that have the following code in GRUB stage1.s code:
lodsb
cmpb $0, %al
jne 1b /* if not end of string, jmp to display */
ret


0000006A F6C280 test dl,0x80
do not probe LBA if the drive is a floppy
0x80 is STAGE1_BIOS_HD_FLAG that explained before.

0000006D 7454 jz 0xc3
Jump to the “0xc3” on the memory if zero flag is set and that named
“chs_mode” and it determine the hard disk geometry from the BIOS! If
it happened first, so that LS-120 IDE floppies work correctly.

0000006F B441 mov ah,0x41
Function 41h of INT13
00000071 BBAA55 mov bx,0x55aa
00000074 CD13 int 0x13
Test for INT13 Extensions
Check if LBA is supported
%dl may have been clobbered by INT 13, AH=41H.
This happens, for example, with AST BIOS 1.04.

00000076 5A pop dx
00000077 52 push dx

00000078 7249 jc 0xc3
0000007A 81FB55AA cmp bx,0xaa55
0000007E 7543 jnz 0xc3
Use CHS if fails
“0xc3” is the place of memory whit label “chs_mode” that I explained
before and will explain more in end of this paper.

00000080 A0417C mov al,[0x7c41] <<<< Force LBA mode byte
00000083 84C0 test al,al
check if AH=0x42 is supported if FORCE_LBA is zero

00000085 7505 jnz 0x8c
Jump if “lba_mode”
00000087 83E101 and cx,byte +0x1
0000008A 7437 jz 0xc3

0000008C 668B4C10 mov ecx,[si+0x10]
Save the total number of sectors

00000090 BE057C mov si,0x7c05
Set %si to the disk address packet

00000093 C644FF01 mov byte [si-0x1],0x1
Set the mode to non-zero

00000097 668B1E447C mov ebx,[0x7c44]

0000009C C7041000 mov word [si],0x10
The size and the reserved byte

000000A0 C744020100 mov word [si+0x2],0x1
The blocks

000000A5 66895C08 mov [si+0x8],ebx
The absolute address (low 32 bits)

000000A9 C744060070 mov word [si+0x6],0x7000
“0x7000” is the segment of buffer address
000000AE 6631C0 xor eax,eax

000000B1 894404 mov [si+0x4],ax

000000B4 6689440C mov [si+0xc],eax

000000B8 B442 mov ah,0x42
000000BA CD13 int 0x13
BIOS call "INT 0x13 Function 0x42" to read sectors from disk into
memory
Call with %ah = 0x42
%dl = drive number
%ds:%si = segment : offset of disk address packet
Return:
%al = 0x0 on success; err code on failure

000000BC 7205 jc 0xc3
LBA read is not supported, so fallback to CHS.

000000BE BB0070 mov bx,0x7000
“0x7000” is STAGE1_BUFFERSEG

000000C1 EB7D jmp short 0x140
“0x140” is copy_buffer

The code below is “chs_mode” that I explained a little before.
Determine the hard disk geometry from the BIOS!
We do this first, so that LS-120 IDE floppies work correctly.

000000C3 B408 mov ah,0x8
Function 08 of INT13

000000C5 CD13 int 0x13
Get Drive Parameters

000000C7 730A jnc 0xd3
The call failed, so maybe use the floppy probe instead.
“0xd3” is the place of label final_init
The call failed, so maybe use the floppy probe instead.

000000C9 F6C280 test dl,0x80
“0x80” is a value of STAGE1_BIOS_HD_FLAG

000000CC 0F84F300 jz near 0x1c3
“0x1c3” is a label whit name: floppy_probe that I will show the
implantation further.

Nope, we definitely have a hard disk, and we're screwed.

000000D0 E98D00 jmp 0x160
Hard disk error  hd_probe_error


000000D3 BE057C mov si,0x7c05
000000D6 C644FF00 mov byte [si-0x1],0x0
set the mode to zero

000000DA 6631C0 xor eax,eax
000000DD 88F0 mov al,dh
save number of heads

the following code is for final initialize:
000000DF 40 inc ax
000000E0 66894404 mov [si+0x4],eax
save number of cylinders

000000E4 31D2 xor dx,dx
000000E6 88CA mov dl,cl
000000E8 C1E202 shl dx,0x2
000000EB 88E8 mov al,ch
000000ED 88F4 mov ah,dh

000000EF 40 inc ax
000000F0 894408 mov [si+0x8],ax

000000F3 31C0 xor ax,ax
000000F5 88D0 mov al,dl
000000F7 C0E802 shr al,0x2

000000FA 668904 mov [si],eax
save number of sectors

the following code is for setup sectors:

000000FD 66A1447C mov eax,[0x7c44]
load logical sector start (bottom half)

00000101 6631D2 xor edx,edx
zero %edx

00000104 66F734 div dword [si]
divide by number of sectors

00000107 88540A mov [si+0xa],dl
save sector start

0000010A 6631D2 xor edx,edx
Zero %edx

0000010D 66F77404 div dword [si+0x4]
divide by number of heads

00000111 88540B mov [si+0xb],dl
save head start

00000114 89440C mov [si+0xc],ax
save cylinder start

00000117 3B4408 cmp ax,[si+0x8]
0000011A 7D3C jnl 0x158
“0x158” is a label with this name geometry_error
do we need too many cylinders?
This is the loop for taking care of BIOS geometry translation (ugh!)

0000011C 8A540D mov dl,[si+0xd]
get high bits of cylinder

0000011F C0E206 shl dl,0x6
shift left by 6 bits

00000122 8A4C0A mov cl,[si+0xa]
get sector

00000125 FEC1 inc cl
normalize sector (sectors go from 1-N, not 0-(N-1) )

00000127 08D1 or cl,dl
composite together

00000129 8A6C0C mov ch,[si+0xc]
sector+hcyl in cl, cylinder in ch

0000012C 5A pop dx
restore %dx

0000012D 8A740B mov dh,[si+0xb]
Head number

BIOS call "INT 0x13 Function 0x2" to read sectors from disk into
memory
Call with %ah = 0x2
%al = number of sectors
%ch = cylinder
%cl = sector (bits 6-7 are high bits of "cylinder")
%dh = head
%dl = drive (0x80 for hard disk, 0x0 for floppy disk)
%es:%bx = segment:offset of buffer
Return:
%al = 0x0 on success; err code on failure

00000130 BB0070 mov bx,0x7000
“0x7000” is STAGE1_BUFFERSEG

00000133 8EC3 mov es,bx
load %es segment with disk buffer

00000135 31DB xor bx,bx
%bx = 0, put it at 0 in the segment

00000137 B80102 mov ax,0x201
0000013A CD13 int 0x13 function 2 of int13

0000013C 722A jc 0x168
“0x168” is labeb with this name: read_error

0000013E 8CC3 mov bx,es

The following code is for copy buffer:

00000140 8E06487C mov es,[0x7c48]
We need to save %cx and %si because the startup code in stage2 uses
them without initializing them.
00000144 60 pusha
00000145 1E push ds

00000146 B90001 mov cx,0x100
00000149 8EDB mov ds,bx
0000014B 31F6 xor si,si
0000014D 31FF xor di,di

0000014F FC cld
00000150 F3A5 rep movsw

00000152 1F pop ds
00000153 61 popa

00000154 FF26427C jmp near [0x7c42] WORD <<< 8000 hex.

boot stage2
This is where we jump to the next stage of the code which GRUB loaded
from the HDD into Memory locations 0000:8000 hex and following:

END OF MAIN LOOP

Section for Displaying Error Messages:
BIOS Geometry translation error (past the end of the disk geometry!).

The following code is for geometry_error:
00000158 BE7C7D mov si,0x7d7c --"Geom Error"
0000015B E84000 call 0x19e -- Display it on screen.
0000015E EB0E jmp short 0x16e -- Finish it and 'lock-
up'
Jump to the label “general_error”

The following code is for hd_probe_error:
Disk probe failure
00000160 BE817D mov si,0x7d81 -- "Hard Disk Error"
00000163 E83800 call 0x19e -- Display it on screen.
00000166 EB06 jmp short 0x16e -- Finish it and 'lock-up'

Read error on the disk:
read_error:
00000168 BE8B7D mov si,0x7d8b -- "Read Error"
0000016B E83000 call 0x19e -- Display it on screen

general_error:
0000016E BE907D mov si,0x7d90 -- (For displaying "
Error")
00000171 E82A00 call 0x19e -- Display it on screen

stop:
00000174 EBFE jmp short 0x174
go here when you need to stop the machine hard after an error
condition

Location of the GRUB ID String
Define string “GRUB ” :
00000176 47
00000177 52
00000178 55
00000179 42
0000017A 20
0000017B 00
Define string “Geom” :
0000017C 47
0000017D 65
0000017E 6F
0000017F 6D
00000180 00

Define string “Hard Disk”:
00000181 48
00000182 61
00000183 72
00000184 64
00000185 20
00000186 44
00000187 69
00000188 73
00000189 6B
0000018A 00

Define string “Read”:
0000018B 52
0000018C 65
0000018D 61
0000018E 64
0000018F 00

Define string “ Error”:
00000190 20
00000191 45
00000192 72
00000193 72
00000194 6F
00000195 72
00000196 00

Display Character Subroutine:
00000197 BB0100 mov bx,0x1

0000019A B40E mov ah,0xe
Function 0Eh of INT10

0000019C CD10 int 0x10
Display the character

0000019E AC lodsb

0000019F 3C00 cmp al,0x0

000001A1 75F4 jnz 0x197
if not end of string, jmp to display
000001A3 C3 ret


000001A4 00
000001A5 00
000001A6 00
000001A7 00
000001A8 00
000001A9 00
000001AA 00
000001A8 00
000001AC 00
000001AD 00
000001AE 00
000001AF 00
000001B0 00
000001B1 00
000001B2 00
000001B3 00
000001B4 00
000001B5 00
000001B6 00
000001B7 00



Finally, GRUB makes sure not to use any of the bytes between offsets
1B8h and 1BBh because they're used by Microsoft® Windows™ NT/2000/XP/
2003 as the NT Drive Serial Number; which in our example above is the
four-byte WORD 00000000h.

000001B8 00
000001B9 00
000001BA 00
000001BB 00

000001BC 00
000001BD 00

Partition Table in Memory:
Although GRUB is a Boot Manager, its stage1 code follows the structure
of all MBRs by placing the standard four-entry Partition Table in its
agreed upon location (offsets 01BEh through 01FDh) which is followed
by the standard Word-sized signature ID of AA55h.
000001BE 80
000001BF 01
000001C0 01
000001C1 00
000001C2 83
000001C3 FE
000001C4 3F
000001C5 0C
000001C6 3F
000001C7 00
000001C8 00
000001C9 00
000001CA 8E
000001CB 2F
000001CC 03
000001CD 00
000001CE 00
000001CF 00
000001D0 01
000001D1 0D
000001D2 83
000001D3 FE
000001D4 BF
000001D5 DE
000001D6 CD
000001D7 2F
000001D8 03
000001D9 00
000001DA 52
000001DB FC
000001DC B0
000001Dd 00
000001DE 00
000001DF 00
000001E0 81
000001E1 DF
000001E2 82
000001E3 FE
000001E4 FF
000001E5 0E
000001E6 1F
000001E7 2C
000001E8 B4
000001E9 00
000001EA 30
000001EB C4
000001EC 0B
000001ED 00
000001EE 00
000001EF 00
000001F0 00
000001E1 00
000001F2 00
000001F3 00
000001F4 00
000001F5 00
000001F6 00
000001F7 00
000001F8 00
000001F9 00
000001FA 00
000001FB 00
000001FC 00
000001FD 00

000001FE 55
000001FF AA

.



Relevant Pages

  • Re: Disk geometry salad...
    ... but lists the number of LBA sectors for each drive. ... > of the hard drives and the CHS geometry, but no LBA sectors) as ... The c/h/s data format used to pass a disk sector address to an ATA disk ... The c/h/s data format used to pass a disk sector address to a BIOS disk ...
    (freebsd-questions)
  • Re: Followup Q to "IBM 120 G IDE -- problems"
    ... > that the BIOS reports. ... limitations of "BIOS" disk addressing, ... usually given as 1024 cylinders, 255 heads, and 63 sectors per track. ... BIOS may pretend that your disk drive has some other geometry, ...
    (freebsd-questions)
  • Re: Correctly configuring an old HDD : Miniscribe 3085
    ... It's a 70MB disk, yes? ... Anyway, whether or not LBA is On or Off, on BIOS splash screen at least ... Usually I set boot order as: ... Sectors Per Cluster: 4 ...
    (uk.comp.homebuilt)
  • Re: OpenBSD failing to boot
    ... My hard disk controller and BIOS support LBA and so does biosboot, ... I should choose heads and sectors values ... will reside on the first sector of my OpenBSD partition, ...
    (comp.unix.bsd.openbsd.misc)
  • GRUB master boot record
    ... the Jump Instruction. ... BIOS parameter block is a description of the physical medium ... as for flexible/floppy and optic distal disk cartridges) also ... installed in the first track (Sectors 1 ff.) of an HDD; ...
    (comp.os.linux.hardware)