Compago

...free knowledge

 
  • Increase font size
  • Default font size
  • Decrease font size
Home Manuali Programmazione Storia di un boot

Storia di un boot

E-mail Stampa PDF
Indice
Storia di un boot
Partition Boot Sector
Dentro la partizione
Tutte le pagine

E' da tanto che non scrivo un articolo. Oggi in un vecchio computer ho trovato un file di testo nel quale avevo analizzato le prime istruzioni che stanno all'inizio di un disco rigido esterno.

So che a molti non interesserà nulla, per altri sarà difficile capire di che si parla, ma secondo me vale la pena di pubblicarlo.

Non è completo ma sicuramente è un buon inizio.

Stiamo parlando dell'Master Boot Record, per chi non sapesse cosa è ->MBR o qui o qui.

L'MBR viene caricato in memoria all'indirizzo 0000:7C00h dal BIOS.
Una delle prime cose che fa è di riposizionarsi in memoria ovvero sposta se stesso in avanti per lasciare spazio al codice che successivamente verrà letto dal disco e caricato in memoria.
In questo modo l'MBR compie le stesse operazioni che fa il BIOS quando avvia il disco e carica l'MBR; ed è questo motivo che gli interrupt usati nel codice dell'MBR sono gli stessi di quelli usati nel BIOS.

0000:7C00 00000000 33C0 xor ax,ax       ;Azzera AX
0000:7C02 00000002 8ED0 mov ss,ax ;Azzera SS (stack segment = 0)
0000:7C04 00000004 BC007C mov sp,0x7c00 ;SP (Stack pointer) = 7C00h
0000:7C07 00000007 FB sti ;Abilita gli interrupt
0000:7C08 00000008 50 push ax ;Inserisce il valore di AX che è zero nello stack per poi assegnarlo al registro ES
0000:7C09 00000009 07 pop es ;ES = 0
0000:7C0A 0000000A 50 push ax ;Inserisce il valore di AX che è zero nello stack per poi assegnarlo al registro DS
0000:7C0B 0000000B 1F pop ds ;DS = 0
0000:7C0C 0000000C FC cld ;Pulisci il flag di direzione ( =0 SI e DI verranno incrementati)
0000:7C0D 0000000D BE1B7C mov si,0x7c1b ;SI = 7C1Bh
0000:7C10 00000010 BF1B06 mov di,0x61b ;DI = 61Bh
0000:7C13 00000013 50 push ax ;inserisce nello stack la prima parte dell'indirizzo a cui saltare in seguito
0000:7C14 00000014 57 push di ;inserisce nello stack l'indirizzo a cui saltare dopo aver riposizionato il blocco di memoria
0000:7C15 00000015 B9E501 mov cx,0x1e5 ;CX = 1E5h (485 byte) è la dimensione del blocco da spostare
0000:7C18 00000018 F3A4 rep movsb ;Sposta l'MBR(485 byte) da 0000:7C1Bh a 0000:061Bh
0000:7C1A 0000001A CB retf ;Salta all'indirizzo 0000:061Bh

Giusto per ricordare, l'istruzione rep ripete la copia dei dati(movsb) per un numero di volte pari al contatore CX(1E5h) quindi in questo caso 485 volte. La copia viene tra l'indirizzo di partenza in SI(7C1Bh) a quello di destinazione in DI(61Bh). Quindi il codice dopo essersi riposizionato in memoria continua la sua esecuzione al nuovo indirizzo in memoria da 61Bh  a 7FFh.

Cerca partizione attiva e verifica che sia l'unica

0000:061B 0000001B BDBE07 mov bp,0x7be      ;Punta il registro BP all'inizio della tabella partizioni 
0000:061E 0000001E B104 mov cl,0x4 ;Imposta il contatore a 4 = numero degli elementi nella tabella delle partizioni
0000:0620 00000020 386E00 cmp [bp+0x0],ch ;Confronta il primo byte della tabella delle partizioni col valore 0,
;dato che CX alla fine dell'istruzione rep era 0 => CH = 0
;se è bootable sarà 80h altrimenti è 0
0000:0623 00000023 7C09 jl 0x62e ;Se è 80h,cioè se è avviabile va all'indirizzo -> 062Eh controlla partizioni
0000:0625 00000025 7513 jnz 0x63a ;Se non è zero vai -> 063Ah stampa messaggio errore "Tabella partizioni non valida"
0000:0627 00000027 83C510 add bp,byte +0x10 ;Se è bootabile passa al prossimo elemento della tabella per verificare che sia l'unica
0000:062A 0000002A E2F4 loop 0x620 ;Ripete andando a 0620h fino a che CX, inizialmente 4, sarà a zero, altrimenti prosegue
0000:062C 0000002C CD18 int 0x18 ;Esegue una funzione in caso di errore del boot (No boot device available)

Giusto per ricordare un po' di linguaggio assembly e non dover ricorrere ad un debugger, i salti locali tipo JNZ o JL e simili sono codificati da una istruzione più la distanza dalla operazione successiva, esempio:

Se l'istruzione di salto JNZ(75) si trova all'indirizzo 0103 e si deve saltare di 13 scriveremo così:

0000:0103 7513
0000:0105 9090

la destinazione del salto sarà l'indirizzo della operazione successiva più la distanza, quindi in questo caso 105h+13h=118h

Alcune istruzioni usano un byte come distanza e per alcune usano un numero con il segno, per indicare un salto in avanti o indietro
quindi occorre ricordare come calcolare un complemento a due.
Esempio 0000:0103 74F4 = JZ (salta se zero) di F4. Cosa è F4? F4 = 11110100 => 00001011 + 1 = 00001100 = C => -C
l'indirizzo di destinazione sarà 105h-Ch=F9h (0000:00f9)

Controlla le altre partizioni nella tabella

0000:062E 0000002E 8BF5 mov si,bp           ;SI=BP = indirizzo tabella partizioni (primo elemento)
0000:0630 00000030 83C610 add si,byte +0x10 ;Passa al secondo elemento
0000:0633 00000033 49 dec cx ;CX inizialmente era 4 ,pari al numero delle partizioni permesse. Viene decrementato
0000:0634 00000034 7419 jz 0x64f ;Se CX è arrivato a zero passa all'esame della partizione trovata attiva inizialmente
0000:0636 00000036 382C cmp [si],ch ;Altrimenti confronta in primo campo dell'elemento della partizione col valore 0
0000:0638 00000038 74F6 je 0x630 ;Se è 0( =non attiva) Ripete -> 630h

Se non è bootable e il valore non è zero stampa un messaggio di errore

S000:063A 0000003A A0B507 mov al,[0x7b5] ;Nella tabelle delle stringhe c'è, nell'elemento all'indirizzo 0x7B5h è contenuto il valore 2Ch
;questo è un offset dove si trova memorizzato il primo carattere della stringa "Tabella delle partizioni non valida"
;infatti 2C sommato all'offset 700 ci da l'indirizzo della stringa 72C

Procedura di stampa

0000:063D 0000003D B407 mov ah,0x07    ;Inserisce un offset in AH di 07, in questo modo AX sarà 07?? dove ?? è specificato in AL 
0000:063F 0000003F 8BF0 mov si,ax ;Inizia il procedimento di stampa
0000:0641 00000041 AC lodsb ;carica il carattere della stringa da stampare a video
0000:0642 00000042 3C00 cmp al,0x0 ;controlla che la stringa sia finita
0000:0644 00000044 74FC jz 0x42 ;Quando è finita la procedura rimane bloccata qui, iterando all'infinito un CMP!!!
0000:0646 00000046 BB0700 mov bx,0x7 ;Imposta parametri della chiamata di interrupt
0000:0649 00000049 B40E mov ah,0xe ;
0000:064B 0000004B CD10 int 0x10 ;Stampa a video il carattere
0000:064D 0000004D EBF2 jmp short 0x63f;Ripeti la procedura di stampa

Se non vi sono altre partizioni attive

0000:064F 0000004F 884E10 mov [bp+0x10],cl ;BP punta all'elemento della tabella delle partizioni relativo a quella attiva; BP+10h (elem.successivo) conterrà il valore di CL = 0 
0000:0652 00000052 E84600 call word 0x9b ;Inizia l'analisi del disco ed eventualmente la lettura -> 69Bh

Dopo la lettura

0000:0655 00000055 732A jnc 0x81                  ;se la lettura è OK va alla verifica dei dati copiati
0000:0657 00000057 FE4610 inc byte [bp+0x10] ;Passa all'elemento successino nella tabella delle partizioni
0000:065A 0000005A 807E040B cmp byte [bp+0x4],0xb ;Verifica che questa nuova partizione sia di tipo FAT
0000:065E 0000005E 740B jz 0x6b ;Se è FAT va a -> 66Bh
0000:0660 00000060 807E040C cmp byte [bp+0x4],0xc ;Se non è FAT controlla che no sia FAT con LBA
0000:0664 00000064 7405 jz 0x6b ;Se è FAT LBA va a -> 66Bh
0000:0666 00000066 A0B607 mov al,[0x7b6] ;Se non è di nessuno di questi tipi inizia la procedura di segnalalazione errore
;All'indirizzo 7B6h c'è il valore 50 ->"Errore nel caricamento del sistema operativo"
0000:0669 00000069 75D2 jnz 0x3d ;salta alla procedura di stampa

Se la partizione è di tipo FAT

0000:066B 0000006B 80460206 add byte [bp+0x2],0x6
0000:066F 0000006F 83460806 add word [bp+0x8],byte +0x6
0000:0673 00000073 83560A00 adc word [bp+0xa],byte +0x0
0000:0677 00000077 E82100 call word 0x9b ;Inizia la procedura di determinazione della geometria e poi passerà alla lettura del disco
0000:067A 0000007A 7305 jnc 0x81 ;se la lettura è OK va alla verifica dei dati copiati
0000:067C 0000007C A0B607 mov al,[0x7b6] ;Se non è di nessuno di questi tipi inizia la procedura di segnalalazione errore
;All'indirizzo 7B6h c'è il valore 50 ->"Errore nel caricamento del sistema operativo"
0000:067F 0000007F EBBC jmp short 0x3d ;salta alla procedura di stampa

Verifica della copia dei dati contenuti nel boot sector puntato dalla tabella delle partizioni

0000:0681 00000081 813EFE7D55AA cmp word [0x7dfe],0xaa55 ;dopo la lettura l'MBR è stato copiato in memoria, adesso verifica che all'indirizzo 7DFEh ci sia il valore AA55h
0000:0687 00000087 740B jz 0x94 ;Se la verifica è andata bene vai a -> 694h
0000:0689 00000089 807E1000 cmp byte [bp+0x10],0x0 ;Se la verifica è andata male confronta il primo campo del successivo elemento della tabella partizioni
0000:068D 0000008D 74C8 jz 0x57 ;Se anche quest'altra partizone non è attiva prosegui la ricerca della partizione attiva
0000:068F 0000008F A0B707 mov al,[0x7b7] ;carica la stringa di errore: all'indirizzo 7B7h c'è il valore 7D ->"Sistema operativo mancante"
0000:0692 00000092 EBA9 jmp short 0x3d ;Inizia la procedura di stampa

Inizia l'esecuzione del nuovo codice

0000:0694 00000094 8BFC mov di,sp
0000:0696 00000096 1E push ds
0000:0697 00000097 57 push di ;SP=DI=indirizzo dello stack pointer ma anche posione del codice copiato
0000:0698 00000098 8BF5 mov si,bp
0000:069A 0000009A CB retf ;Passa all'esecuzioe del codice che sta nel boot sector puntato dalla partition table (BP=SI=indirizzo partition table entry)

Determina geometria HD (CHS)

0000:069B 0000009B BF0500 mov di,0x5      ; DI = 5 Imposta il contatore per il numero di volte che può ritentare la lettura
0000:069E 0000009E 8A5600 mov dl,[bp+0x0] ; DL = 80 ( = first hard disk)
0000:06A1 000000A1 B408 mov ah,0x8 ;parametro per int 13
0000:06A3 000000A3 CD13 int 0x13 ;Recupera i parametri del disco : DL=numero drive; DH=max. testine; CX=max cilindri e settori
0000:06A5 000000A5 7223 jc 0xca ;Se si verifica un errore vai a -> 6CAh
0000:06A7 000000A7 8AC1 mov al,cl ; CL,dopo la INT 13, contiene il numero mx di settori nei primi 6 bit e il max di cilindri negli ultimi 2
0000:06A9 000000A9 243F and al,0x3f ; mette in AL il numero max di settori
0000:06AB 000000AB 98 cbw ; Lo trasforma in word
0000:06AC 000000AC 8ADE mov bl,dh ; BL = DL = max num. di drive
0000:06AE 000000AE 8AFC mov bh,ah ; BH = AH = 0 se non ci sono errori
0000:06B0 000000B0 43 inc bx ; incrementa BX che conteneva il max indice di drive, che pero iniziava da 0, quindi il numero di drives è dato da DL+1
0000:06B1 000000B1 F7E3 mul bx ; moltiplica il numero di drive per il numero di settori e lo inserisce in DX:AX = BX*AX
0000:06B3 000000B3 8BD1 mov dx,cx ;Sposta in DX il contenuto di CX (informazioni sui cilindri e settori)
0000:06B5 000000B5 86D6 xchg dl,dh ;Inverte DH e DL in modo da avere in DL i primi 8 bit del numero di cilindri
0000:06B7 000000B7 B106 mov cl,0x6 ;inserisce in CL
0000:06B9 000000B9 D2EE shr dh,cl ;DH conteneva il vecchio valore di CL; gli ultimi 2 bit di CL vengono spostati e che andranno a completare l'indice massimo di cilindri in DX
0000:06BB 000000BB 42 inc dx ;dato che gli indici partono da 0 per avere il massimo numero di cilindri bisogna incrementarlo di 1
0000:06BC 000000BC F7E2 mul dx ;Moltiplica il numero di cilindri per il risultato della moltiplicazione precedente e lo mette in DX:AX = DX*AX
;In questo modo ottiene il numero totale di settori
0000:06BE 000000BE 39560A cmp [bp+0xa],dx ;?? Confronta il numero totale di settori con la word alta relativa al numero di settori pecedenti la partizione
;Se la partizione è all'inizio del disco questo valore sarà 0
0000:06C1 000000C1 7723 ja 0xe6 ;Se la sua posizione è maggiore del numero di settori raggiungibili in coordinate CHS alloa prova supporto LBA -> 6E6h
0000:06C3 000000C3 7205 jc 0xca ;Se la posizione ricade entro i limiti dell'indirizzamento CHS del disco allora procede nella lettura semplice -> 6CAh
0000:06C5 000000C5 394608 cmp [bp+0x8],ax ;??
0000:06C8 000000C8 731C jnc 0xe6 ;Prova supporto LBA -> 6E6h

Procedura di lettura del disco:

0000:06CA 000000CA B80102 mov ax,0x201    ;Imposta i parametri per la lettura dal disco : AH = 02(funz. lett) AL = 1 (N°settori) 
0000:06CD 000000CD BB007C mov bx,0x7c00 ;Indirizzo di destinazione, cioè dove verranno salvati i dati
0000:06D0 000000D0 8B4E02 mov cx,[bp+0x2] ;CX = 0100 (BP punta alla tabella partizioni) => CH = 1 (cilindro) CL = 0 (settore)
0000:06D3 000000D3 8B5600 mov dx,[bp+0x0] ;DX = 8001 => DL = 1 (head) DH = 80 (7bit drive num. = 0)
0000:06D6 000000D6 CD13 int 0x13 ;Chiama la routine di interrupt 13 (AH=02h),che legge dei settori dal disco e li salva in memoria (ES:BX = 0000:7C00)
0000:06D8 000000D8 7351 jnc 0x12b ;Se non ci sono errori va a -> 72Bh
0000:06DA 000000DA 4F dec di ;Inizialmente prima era 5 e di volta in volta viene decrementato il contatore per i tentativi di lettura
0000:06DB 000000DB 744E jz 0x12b ;Se il contatore DI=0 allora smette di provare a leggere e ritorna al codice iniziale a -> 72Bh
0000:06DD 000000DD 32E4 xor ah,ah ;altrimenti ci sono errori e inizia la procesura di reset, imposta AH = 0
0000:06DF 000000DF 8A5600 mov dl,[bp+0x0] ;Indica il drive da resettare è il primo DL = 80h
0000:06E2 000000E2 CD13 int 0x13 ;Chiama la routine di interrupt 13 (AH 0h) per il reset del system disk
0000:06E4 000000E4 EBE4 jmp short 0xca ;Prova a ripetere la lettura

Prova il supporto LBA

0000:06E6 000000E6 8A5600 mov dl,[bp+0x0] ;DL = 80h = indica il primo hard disk
0000:06E9 000000E9 60 pushaw
0000:06EA 000000EA BBAA55 mov bx,0x55aa ;Inizia a impostare i parametri per la chiamata di interrupt
0000:06ED 000000ED B441 mov ah,0x41 ;
0000:06EF 000000EF CD13 int 0x13 ;Chiama la routine di interrupt 13 (AH=41h), che testa il supporto delle estensioni nel bios
0000:06F1 000000F1 7236 jc 0x129 ;Va a -> 729h in caso di errore
0000:06F3 000000F3 81FB55AA cmp bx,0xaa55 ;Verifica se è installato il supporto LBA
0000:06F7 000000F7 7530 jnz 0x129 ;se non è supportato va a -> 729h in caso di errore
0000:06F9 000000F9 F6C101 test cl,0x1 ;Verifica se il dispositivo supporta l'uso di strutture "a pacchetto" per la prossima chiamata
0000:06FC 000000FC 742B jz 0x129 ;Se non supportate va a -> 729h
0000:06FE 000000FE 61 popaw
0000:06FF 000000FF 60 pushaw
0000:0700 00000100 6A00 push byte +0x0 ;Inserisce nello stack una serie di valori che poi costituiranno il "pacchetto" di parametri usato dalla chiamata INT 13
0000:0702 00000102 6A00 push byte +0x0
0000:0704 00000104 FF760A push word [bp+0xa]
0000:0707 00000107 FF7608 push word [bp+0x8]
0000:070A 0000010A 6A00 push byte +0x0
0000:070C 0000010C 68007C push word 0x7c00
0000:070F 0000010F 6A01 push byte +0x1
0000:0711 00000111 6A10 push byte +0x10
0000:0713 00000113 B442 mov ah,0x42 ;imposta i parametri per la chiamata int 13
0000:0715 00000115 8BF4 mov si,sp
0000:0717 00000117 CD13 int 0x13 ;Chiama la routine di interrupt 13 (AH 42h) che legge i settori del disco in modalità LBA
;I parametri della lettura li prende dalla posizione di memoria DS:SI che ora punta allo stack
; dove aveva inserito i valori 10 | 00 | 01 00 | 00 7C 00 00 | 3F 00 00 00 00 00 00 00
; 10 1 0000:7C00 3F
; dim Ris. N°block Dest. buff. source sector
;In questo modo viene copiato un settore che inizia dopo 3Fh(63) settori e quindi dal byte 7E00h(63*512)
;e viene salvato in memoria a partire dall'indirizzo 0000:7C00 in pratica dove era stato inizialmente caricato questo codice
0000:0719 00000119 61 popaw
0000:071A 0000011A 61 popaw
0000:071B 0000011B 730E jnc 0x12b ;Verifica se l'operazione è riuscita e se si va a 12Bh
0000:071D 0000011D 4F dec di
0000:071E 0000011E 740B jz 0x12b ;se OK va a 72Bh
0000:0720 00000120 32E4 xor ah,ah
0000:0722 00000122 8A5600 mov dl,[bp+0x0]
0000:0725 00000125 CD13 int 0x13 ;Chiama la routine di interrupt 13 (AH 0h) per il reset del system disk
0000:0727 00000127 EBD6 jmp short 0xff ;Ripeti operazione

Arriva qui in caso di errore nel test LBA

0000:0729 00000129 61 popaw
0000:072A 0000012A F9 stc

Finita la lettura ritorna al codice iniziale

0000:072B 0000012B C3 ret

Stringhe

0000:072C 0000012C 546162656C6C6120 "Tabella delle partizioni non valida"
64656C6C65207061
7274697A696F6E69
206E6F6E2076616C
69646100
0000:0750 00000150 4572726F7265206E "Errore nel caricamento del sistema operativo"
656C206361726963
616D656E746F2064
656C207369737465
6D61206F70657261
7469766F00
0000:077D 0000017D 53697374656D6120 "Sistema operativo mancante"
6F70657261746976
6F206D616E63616E
746500
0000:0798 00000198 00
... ...
0000:07B4 000001B4 00
0000:07B5 000001B5 2C ;Indirizzo parziale (7+2C) stringa: "Tabella delle partizioni non valida"
0000:07B6 000001B6 50 ;Indirizzo parziale (7+50) stringa: "Errore nel caricamento del sistema operativo"
0000:07B7 000001B7 7D ;Indirizzo parziale (7+7D) stringa: "Sistema operativo mancante"
0000:07B8 000001B8 FF
0000:07B9 000001B9 56
0000:07BA 000001BA FF5600
0000:07BD 000001BD 00

Tabella delle partizioni

0000:07BE 000001BE 80 Indicatore di boot (attiva)
0000:07BF 000001BF 010100 Coordinate CHS primo blocco partizione
0000:07C2 000001C2 07 Identificativo filesystem (NTFS)
0000:07C3 000001C3 FEFFFF Coordinate CHS ultimo blocco partizione
0000:07C6 000001C6 3F000000 Numero blocchi prima della partizione (inizio dopo 63 blocchi = 7E00h byte)
0000:07CA 000001CA C14BA112 Numero blocchi della partizione (160031015424 byte = 160GB)
0000:07CE 000001CE 00
... ...
0000:07FD 000001FD 00
0000:07FE 000001FE 55AA Master Boot signature

 



Ultimo aggiornamento ( Martedì 31 Maggio 2016 16:22 )  
Loading

Login




Chiudi