2.1.2 Il MBR - Master Boot Record

Il master boot record, o MBR, è il primo settore di un disco (cilindro 0, testina 0, settore 1) ed è destinato a contenere le informazioni essenziali per l’avvio del sistema (v. fig. 2.3).


pict
Figura 2.3: Schematizzazione del MBR.

Come ogni settore del disco, il MBR ha una dimensione di 512 byte, di cui i primi 446 sono destinati a contenere il MBP (Master Boot Program), cioè le istruzioni da eseguire quando viene avviato il disco, mentre i rimanenti 66 byte costituiscono la partition table, ovvero le informazioni sul partizionamento del disco. In particolare la partition table vera e propria si compone di 4 elementi (entry), di 16 byte l’uno, che descrivono le partizioni primarie (al massimo 4 partizioni primarie, o 3 primarie ed una estesa) in cui può essere suddiviso il disco. Ogni elemento contiene le informazioni riportate nella tab. 2.1.


Byte-|Contenuto---------------------------------------|
0---|Indicatore-di boot (contiene il valore 80H-se-la partizione`e attiva)
1-3  |testina, settore e cilindro del primo blocco della partizione
4   |Identificatore del filesystem contenuto nella partizione     |
5-7  |testina, settore e cilindro dell’ultimo blocco della partizione
8-12-1115 |NNuummeerroo d dii b blolocccchhii pr chimea codsetilltuai pscaortnizoi laonepartizione         |
------------------------------------------------------

Tabella 2.1: Partition table entry.

Non è detto che i valori di testina, settore e cilindro del primo e dell’ultimo blocco di ogni partizione siano ognuno memorizzati su un byte. Considerando hard disk con capacità di 10 MiB, si possono avere architetture con 256 testine, 64 settori e 1220 cilindri. Pertanto il numero di testine sarà rappresentato esattamente su un byte, mentre per i settori saranno sufficienti 6 bit, cosicché, visto che un byte non sarebbe sufficiente per rappresentare i cilindri, vengono utilizzati i 2 bit più significativi del byte che riporta i settori e considerati come i 2 bit più significativi da aggiungere ad un byte per formare così 10 byte per memorizzare il numero di cilindri. Ma con 10 byte si possono memorizzare soltanto valori da 0 a 1023. Quindi, per com’è stato realizzato il MBR, lo SBP dovrebbe essere contenuto nei primi 1024 cilindri del disco (cioè nei primi 8 GiB), altrimenti il BIOS non sarà in grado di raggiungerlo e quindi il sistema operativo non potrà essere caricato. Per ovviare questo problema, nelle versioni più recenti dei BIOS è possibile utilizzare la traduzione dell’indirizzamento dei settori LBA (come accennato nella sez. 1.8). Questo pemette di oltrepassare il limite sull’indirizzamento dei cilindri suddetto.

Gli ultimi 2 byte delle partition table sono un identificativo di riconoscimento della fine del MBR e contengono il valore AA55H (si ricordi che i PC utilizzano la convenzione little endian per la memorizzazione delle informazioni)4.

Un esempio del contenuto di un MBR è riportato di seguito (si tratta del MBR di GRUB, v. sez. 2.1.6).

00000000  eb 48 90 d0 bc 00 7c fb  50 07 50 1f fc be 1b 7c  |.H....|.P.P....||
00000010  bf 1b 06 50 57 b9 e5 01  f3 a4 cb be be 07 b1 04  |...PW...........|
00000020  38 2c 7c 09 75 15 83 c6  10 e2 f5 cd 18 8b 14 8b  |8,|.u...........|
00000030  ee 83 c6 10 49 74 16 38  2c 74 f6 be 10 07 03 02  |....It.8,t......|
00000040  80 00 00 80 64 6b ce 00  00 08 fa ea 50 7c 00 00  |....dk......P|..|
00000050  31 c0 8e d8 8e d0 bc 00  20 fb a0 40 7c 3c ff 74  |1....... ..@|<.t|
00000060  02 88 c2 52 be 76 7d e8  34 01 f6 c2 80 74 54 b4  |...R.v}.4....tT.|
00000070  41 bb aa 55 cd 13 5a 52  72 49 81 fb 55 aa 75 43  |A..U..ZRrI..U.uC|
00000080  a0 41 7c 84 c0 75 05 83  e1 01 74 37 66 8b 4c 10  |.A|..u....t7f.L.|
00000090  be 05 7c c6 44 ff 01 66  8b 1e 44 7c c7 04 10 00  |..|.D..f..D|....|
000000a0  c7 44 02 01 00 66 89 5c  08 c7 44 06 00 70 66 31  |.D...f.\..D..pf1|
000000b0  c0 89 44 04 66 89 44 0c  b4 42 cd 13 72 05 bb 00  |..D.f.D..B..r...|
000000c0  70 eb 7d b4 08 cd 13 73  0a f6 c2 80 0f 84 f3 00  |p.}....s........|
000000d0  e9 8d 00 be 05 7c c6 44  ff 00 66 31 c0 88 f0 40  |.....|.D..f1...@|
000000e0  66 89 44 04 31 d2 88 ca  c1 e2 02 88 e8 88 f4 40  |f.D.1..........@|
000000f0  89 44 08 31 c0 88 d0 c0  e8 02 66 89 04 66 a1 44  |.D.1......f..f.D|
00000100  7c 66 31 d2 66 f7 34 88  54 0a 66 31 d2 66 f7 74  ||f1.f.4.T.f1.f.t|
00000110  04 88 54 0b 89 44 0c 3b  44 08 7d 3c 8a 54 0d c0  |..T..D.;D.}<.T..|
00000120  e2 06 8a 4c 0a fe c1 08  d1 8a 6c 0c 5a 8a 74 0b  |...L......l.Z.t.|
00000130  bb 00 70 8e c3 31 db b8  01 02 cd 13 72 2a 8c c3  |..p..1......r*..|
00000140  8e 06 48 7c 60 1e b9 00  01 8e db 31 f6 31 ff fc  |..H|`......1.1..|
00000150  f3 a5 1f 61 ff 26 42 7c  be 7c 7d e8 40 00 eb 0e  |...a.&B|.|}.@...|
00000160  be 81 7d e8 38 00 eb 06  be 8b 7d e8 30 00 be 90  |..}.8.....}.0...|
00000170  7d e8 2a 00 eb fe 47 52  55 42 20 00 47 65 6f 6d  |}.*...GRUB .Geom|
00000180  00 48 61 72 64 20 44 69  73 6b 00 52 65 61 64 00  |.Hard Disk.Read.|
00000190  20 45 72 72 6f 72 00 bb  01 00 b4 0e cd 10 ac 3c  | Error.........<|
000001a0  00 75 f4 c3 00 00 00 00  00 00 00 00 00 00 00 00  |.u..............|
000001b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 80 01  |................|
000001c0  01 00 0b fe ff 47 3f 00  00 00 09 e9 cd 00 00 00  |.....G?.........|
000001d0  c1 48 83 fe ff 51 48 e9  cd 00 8a 73 02 00 00 00  |.H...QH....s....|
                                                                        
                                                                        
000001e0  c1 52 83 fe ff ff d2 5c  d0 00 54 58 53 00 00 fe  |.R.....\..TXS...|
000001f0  ff ff 0f fe ff ff 26 b5  23 01 20 d8 07 00 55 aa  |......&.#. ...U.|
Prima di effettuare qualsiasi operazione sul MBR è caldamente consigliato di effettuarne una copia di backup in modo da poterlo eventualmente rirpistinare nel caso in cui le modifiche effettuate dessero dei problemi. Il backup e l’eventuale ripristino del MBR può essere effettuato per mezzo del comando dd (man page dd(1)) che copia fisicamente i byte da un media in un altro.

____________________________________________________________________

Comando: dd
Path: /bin/dd

SINTASSI  
# dd [option]  
DESCRIZIONE

bytes e num possono essere valori numerici seguiti dai suffissi moltiplicativi illustrati nella tab. 2.3.


|-Suffisso-|--------------Significato-|
|-c------|---------------(default) 1|
| w      |                     2 |
| b      |                    512 |
| kB      |                   1000 |
| KMB      |                10010002400 |
| M      |                1048576 |
| GB      |             1000000000 |
| G      |             1073741824 |
| TBT      |           11000099050101060207070076 |
| PB      |        1000000000000000 |
| P      |        1125899906842624 |
| EB      |     1000000000000000000 |
| EZB      |   10010105020902010500400600060804060907600 |
| Z      |   1180591620717411303424 |
| YB      |1000000000000000000000000 |
--Y-------1208925819614629174706176--

Tabella 2.3: Suffissi utilizzabili con dd.

________________________________________________________________________

Le informazioni contenute nel MBR di un disco possono essere salvate in un file con un comando analogo a quello seguente

# dd if=/dev/hda of=/boot/boot.MBR bs=512 count=1
In questo modo vengono fisicamente copiati i byte contenuti nel primo settore (512 byte) del primo disco ATA (/dev/hda) nel file /boot/boot.MBR.

Per ripristinare successivamente il MBR con le informazioni contenute in un file si può utilizzare il comando seguente

# dd if=/boot/boot.MBR of=/dev/hda bs=512 count=1
In questo modo vengono rimpiazzati i byte contenuti nel primo settore (512 byte) del primo disco ATA (/dev/hda) con quelli contenuti nel file /boot/boot.MBR. Così facendo viene ripristinato quindi sia il MBP che la partition table. Nel caso in cui non si voglia ripristinare la partition table occorre ripristinare soltanto i primi 446 byte del MBR (ovvero non considerare gli ultimi 66 byte, contenenti appunto la partition table), con il seguente comando

# dd if=/boot/boot.MBR of=/dev/hda bs=446 count=1

È possibile ripristinare il MBR anche da DOS, lanciando il comando

C:\>FDISK /MBR
     
oppure

C:\>FIXMBR
     
dipendentemente dallo specifico sistema operativo considerato.

È evidente che per far ciò deve essere possibile avviare il sistema. Visto che il MBR è il settore di boot necessario per l’avvio del sistema, è opportuno creare un dischetto di avvio, in maniera da poter avviare il sistema senza aver bisogno del MBR, come descritto nella sez. 2.1.3.

Subito dopo il POST, viene generalmente chiamato l’interrupt 19H, che tenta di leggere il boot sector dal primo disco avviabile (in genere la sequenza dei dischi consultati per l’avvio è: floppy disk, CD-ROM, hard disk). Il primo settore di boot disponibile (nella sequenza dei dispositivi consultati) viene caricato in memoria a partire dalla locazione 7C00H e viene eseguito (il registro SI viene inizializzato con il valore dell’indirizzo della prima locazione relativa alla riga della partition table che descrive la partizione dalla quale è stato caricato il boot record).

Se la word contenuta a partire dalla locazione 0000 : 0472H è diversa da 1234H l’interrupt 19H effettuerà un test della memoria centrale prima di caricare il boot sector.

Il boot di un sistema basato su architettura Intel X386 è un processo piuttosto complesso, poiché inizialmente la CPU funziona in modalità reale5, potendo accedere soltanto al primo MiB di memoria, quindi il boot loader caricherà il sistema operativo (nel caso di GNU/Linux, si tratta del kernel) all’interno del primo MiB di memoria, che una volta avviato in esecuzione, provvederà a far passare la CPU alla modalità protetta e quindi avere a disposizione tutta la memoria fisicamente installata sul sistema.

Di seguito sono riportate, sia la parte dati che le istruzioni assembly X386 (v. cap. 15), secondo lo standard Intel, corrispondenti al codice macchina del MBR visto precedentemente (già rilocato a partire dall’indirizzo 7C00H), per meglio illustrarne il funzionamento.

0000:7c00  eb 48 90 d0 bc 00 7c fb  50 07 50 1f fc be 1b 7c  |.H....|.P.P....||
0000:7c10  bf 1b 06 50 57 b9 e5 01  f3 a4 cb be be 07 b1 04  |...PW...........|
0000:7c20  38 2c 7c 09 75 15 83 c6  10 e2 f5 cd 18 8b 14 8b  |8,|.u...........|
0000:7c30  ee 83 c6 10 49 74 16 38  2c 74 f6 be 10 07 03 02  |....It.8,t......|
0000:7c40  80 00 00 80 64 6b ce 00  00 08 fa ea 50 7c 00 00  |....dk......P|..|
0000:7d70  7d e8 2a 00 eb fe 47 52  55 42 20 00 47 65 6f 6d  |}.*...GRUB .Geom|
0000:7d80  00 48 61 72 64 20 44 69  73 6b 00 52 65 61 64 00  |.Hard Disk.Read.|
0000:7d90  20 45 72 72 6f 72 00 bb  01 00 b4 0e cd 10 ac 3c  | Error.........<|
0000:7da0  00 75 f4 c3 00 00 00 00  00 00 00 00 00 00 00 00  |.u..............|
0000:7db0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 80 01  |................|
0000:7dc0  01 00 0b fe ff 47 3f 00  00 00 09 e9 cd 00 00 00  |.....G?.........|
0000:7dd0  c1 48 83 fe ff 51 48 e9  cd 00 8a 73 02 00 00 00  |.H...QH....s....|
0000:7de0  c1 52 83 fe ff ff d2 5c  d0 00 54 58 53 00 00 fe  |.R.....\..TXS...|
0000:7df0  ff ff 0f fe ff ff 26 b5  23 01 20 d8 07 00 55 aa  |......&.#. ...U.|
0000:7c00 eb 48                 jmp    0x7c4a            Continua l’esecuzione dalla locazione 7C4AH
 
    Inizio
0000:7c4a fa                    cli                      Disabilita gli interrupt
0000:7c4b ea 50 7c 00 00        ljmp   0x0,0x7c50        Continua l’esecuzione dalla locazione 0000 : 7C50 H. Questo serve perché altrimenti certi BIOS possono dare problemi
0000:7c50 31 c0                 xor    ax,ax             Azzera AX
0000:7c52 8e d8                 mov    ds,ax             Azzera DS
0000:7c54 8e d0                 mov    ss,ax             Azzera SS
0000:7c56 bc 00 20              mov    sp,0x2000         SP = 2000H
0000:7c59 fb                    sti                      Abilita gli interrupt
0000:7c5a a0 40 7c              mov    al,ds:0x7c40      Check if we have a forced disk reference here
0000:7c5d 3c ff                 cmp    al,0xff           Confronta AL con FFH
0000:7c5f 74 02                 je     0x7c63            Se AL è 80H, Invalid drive: continua l’esecuzione da 7C63H
0000:7c61 88 c2                 mov    dl,al             DL = AL
0000:7c63 52                    push   dx                Salva DX nello stack
 
    Visualizza il messaggio “GRUB ”
0000:7c64 be 76 7d              mov    si,0x7d76        
0000:7c67 e8 34 01              call   0x7d9e            Chiama la routine di visualizzazione che inizia a 7D9EH
0000:7c6a f6 c2 80              test   dl,0x80           Esegui l’AND tra DL e 80 H
0000:7c6d 74 54                 je     0x7cc3            Se l’AND ha dato come risultato 0, non si tratta di un HD: continua l’esecuzione da 7CC3H
 
    Prova con il supporto LBA
0000:7c6f b4 41                 mov    ah,0x41          
0000:7c71 bb aa 55              mov    bx,0x55aa        
0000:7c74 cd 13                 int    0x13              Chiama la routine di interrupt 13H (AH=41H), che testa il supporto LBA del BIOS
0000:7c76 5a                    pop    dx                Ripristina il contenuto di DX con quello salvato nello stack (con alcuni BIOS il contenuto di DL potrebbe essere variato dopo la chiamata all’interrupt 13H)
0000:7c77 52                    push   dx               
0000:7c78 72 49                 jb     0x7cc3            LBA non supportato: continua da 7CC3 H (prova con CHS)
0000:7c7a 81 fb 55 aa           cmp    bx,0xaa55        
0000:7c7e 75 43                 jne    0x7cc3            LBA non supportato: continua da 7CC3 H (prova con CHS)
    Test se AH=42H è supportato se FORCE LBA è zero
0000:7c80 a0 41 7c              mov    al,ds:0x7c41     
0000:7c83 84 c0                 test   al,al            
0000:7c85 75 05                 jne    0x7c8c            LBA supportato: esegui da 7C8C H
0000:7c87 83 e1 01              and    cx,0x1           
0000:7c8a 74 37                 je     0x7cc3            LBA non supportato: esegui da 7CC3 H (prova con CHS)
 
    LBA
0000:7c8c 66 8b 4c 10           mov    ecx,[si+0x10]    
0000:7c90 be 05 7c              mov    si,0x7c05         Disk address packet
0000:7c93 c6 44 ff 01           mov    [si-0x01],0x01   
0000:7c97 66 8b 1e 44 7c        mov    ebx,0x7c44        Settore relativo allo stage2
0000:7c9c c7 04 10 00           mov    [si],0x10        
0000:7ca0 c7 44 02 01 00        mov    [si+0x02],0x01   
0000:7ca5 66 89 5c 08           mov    [si+0x08],ebx    
0000:7ca9 c7 44 06 00 70        mov    [si+0x06],0x7000 
0000:7cae 66 31 c0              xor    eax,eax          
0000:7cb1 89 44 04              mov    [si+0x04],ax     
0000:7cb4 66 89 44 0c           mov    [si+0x0c],eax    
0000:7cb8 b4 42                 mov    ah,0x42          
0000:7cba cd 13                 int    0x13              Chiama la routine di interrupt 13H (AH=42H), che legge i settori dal disco in modalità LBA
0000:7cbc 72 05                 jb     0x7cc3            LBA non supportato: continua da 7CC3 H (prova con CHS)
0000:7cbe bb 00 70              mov    bx,0x7000        
0000:7cc1 eb 7d                 jmp    0x7d40            Continua da 7D40H
 
    Determina la geometria dell’HD (CHS)
0000:7cc3 b4 08                 mov    ah,0x8           
0000:7cc5 cd 13                 int    0x13              Chiama la routine di interrupt 13H (AH=08H), che legge la geometria CHS del disco
0000:7cc7 73 0a                 jae    0x7cd3            Tutto ok, continua da 7CD3 H
0000:7cc9 f6 c2 80              test   dl,0x80          
0000:7ccc 0f 84 f3 00           je     0x7dc3            Non si tratta di un HD: continua da 7DC3 H (tale indirizzo si trova dentro la partition table - per un HD - infatti viene preso in considerazione soltanto in caso di floppy disk)
0000:7cd0 e9 8d 00              jmp    0x7d60            Continua da 7D60H
0000:7cd3 be 05 7c              mov    si,0x7c05        
0000:7cd6 c6 44 ff 00           mov    [si-0x01],0x00   
    Salva il numero di testine
0000:7cda 66 31 c0              xor    eax,eax          
0000:7cdd 88 f0                 mov    al,dh            
0000:7cdf 40                    inc    ax               
0000:7ce0 66 89 44 04           mov    [si+0x04],eax    
0000:7ce4 31 d2                 xor    dx,dx            
0000:7ce6 88 ca                 mov    dl,cl            
0000:7ce8 c1 e2 02              shl    dx,0x2           
0000:7ceb 88 e8                 mov    al,ch            
0000:7ced 88 f4                 mov    ah,dh            
    Salva il numero di cilindri
0000:7cef 40                    inc    ax               
0000:7cf0 89 44 08              mov    [si+0x08],ax     
0000:7cf3 31 c0                 xor    ax,ax            
0000:7cf5 88 d0                 mov    al,dl            
0000:7cf7 c0 e8 02              shr    al,0x2           
    Salva il numero di settori
0000:7cfa 66 89 04              mov    [si],eax         
 
    Carica lo stage 2 (bottom half)
0000:7cfd 66 a1 44 7c           mov    eax,ds:0x7c44    
0000:7d01 66 31 d2              xor    edx,edx          
0000:7d04 66 f7 34              div    [si]             
0000:7d07 88 54 0a              mov    [si+0x0a],dl      Salva il settore iniziale
0000:7d0a 66 31 d2              xor    edx,edx          
0000:7d0d 66 74 04              div    [si+0x04]        
0000:7d11 88 54 0b              mov    [si+0x0b],dl      Salva la testina iniziale
0000:7d14 89 44 0c              mov    [si+0x0c],ax      Salva il cilindro iniziale
0000:7d17 3b 44 08              cmp    ax,[si+0x08]     
0000:7d1a 7d 3c                 jge    0x7d58            Geometria HD errata: continua da 7D58 H
    Calcolo CHS (BIOS geometry translation)
0000:7d1c 8a 54 0d              mov    dl,[si+0x0d]     
0000:7d1f c0 e2 06              shl    dl,0x6           
0000:7d22 8a 4c 0a              mov    cl,[si+0x0a]     
0000:7d25 fe c1                 inc    cl               
0000:7d27 08 d1                 or     cl,dl            
0000:7d29 8a 6c 0c              mov    ch,[si+0x0c]      Settore e parte più significativa del cilindro in CL, parte meno significativa del cilindro in CH
0000:7d2c 5a                    pop    dx               
0000:7d2d 8a 74 0b              mov    dh,[si+0x0b]      Testina in DH
0000:7d30 bb 00 70              mov    bx,0x7000        
0000:7d33 8e c3                 mov    es,bx            
0000:7d35 31 db                 xor    bx,bx            
0000:7d37 b8 01 02              mov    ax,0x0201        
0000:7d3a cd 13                 int    0x13              Chiama la routine di interrupt 13H (AH=02H), che legge settori dal disco (CHS)
0000:7d3c 72 2a                 jb     0x7d68            Errore nella lettura dal disco: continua da 7D68H
0000:7d3e 8c c3                 mov    bx,es            
 
    Copia il contenuto del buffer appena letto, in un altra zona di memoria
0000:7d40 8e 06 48 7c           mov    es,[0x7c48]      
0000:7d44 60                    pusha                   
0000:7d45 1e                    push   ds               
0000:7d46 b9 00 01              mov    cx,0x0100        
0000:7d49 8e db                 mov    ds,bx            
0000:7d4b 31 f6                 xor    si,si            
0000:7d4d 31 ff                 xor    di,di            
0000:7d4f fc                    cld                     
0000:7d50 f3 a5                 repz movs es:[di],ds:[si]
0000:7d52 1f                    pop    ds               
0000:7d53 61                    popa                    
0000:7d54 ff 26 42 7c           jmp    [0x7c42]          Continua dall’indirizzo contenuto in 7C42 H (lo stage2)
 
    Visualizza “Geom”
0000:7d58 be 7c 7d              mov    si,0x7d7c        
0000:7d5b e8 40 00              call   0x7d9e            Esegui la routine che inizia da 7D9E H
0000:7d5e eb 0e                 jmp    0x7d6e            Continua da 7D6EH
 
    Visualizza “Hard Disk”
0000:7d60 be 81 7d              mov    si,0x7d81        
0000:7d63 e8 38 00              call   0x7d9e            Esegui la routine che inizia da 7D9E H
0000:7d66 eb 06                 jmp    0x7d6e            Continua da 7D6EH
 
    Visualizza “Read”
0000:7d68 be 8b 7d              mov    si,0x7d8b        
0000:7d6b e8 30 00              call   0x7d9e            Esegui la routine che inizia da 7D9E H
 
    Visualizza “ Error”
0000:7d6e be 90 7d              mov    si,0x7d90        
0000:7d71 e8 2a 00              call   0x7d9e            Esegui la routine che inizia da 7D9E H
0000:7d74 eb fe                 jmp    0x7d74            STOP !
 
    Subroutine visualizzazione messaggio (a partire da ds:[si])
0000:7d97 bb 01 00              mov    bx,0x01          
0000:7d9a b4 0e                 mov    ah,0xe           
0000:7d9c cd 10                 int    0x10              Chiama la routine di interrupt 10H (AH=0EH), che visualizza un carattere sullo schermo
0000:7d9e ac                    lods   al,ds:[si]        Copia il carattere da visualizzare in AL
0000:7d9f 3c 00                 cmp    al,0x00           Confronta AL con 0
0000:7da1 75 f4                 jne    0x7d97            Se il carattere non è 0 continua da 7D97 H (visualizzalo)
0000:7da3 c3                    ret                      Ritorna all’istruzione successiva all’ultima CALL dalla quale eri provenuto