Hogyan írjunk saját BootManagert - II. rész

 

Ebben a részben két BIOS szoftvermegszakítás használatát fogjuk megtárgyalni. Ha valaki ki szeretné próbálni a rutinok használatát, arra kérem hogy csak nagyon óvatosan tegye és csak az olvasási funkciókat tesztelje. Ha nem vagyunk elég körültekintőek, könnyen visszafordíthatatlan károkat okozhatunk a merevlemezünknek.

 

Szektorok írására és olvasására létezik több BIOS szolgáltatás is. Mindegyik a 013H-as megszakítással hívható meg. Az ah=2 és ah=3 interruptoknál fizikai szektorszámot kell megadni, vagyis egy 8bites fej, 10bites cilinder és 6bites szektorszámot. A meghajtó számát pedig a dl regiszterbe kell tölteni. 080H az első merevlemezes meghajtó, 081H a második és így tovább.

 

 

Szektor olvasás:

 

Int 013H

AH = 2

DL = meghajtó azonosító

DH = fejszám

CH = sávszám           ; 8bit +2 lásd az előző részben

CL = szektorszám      ;6bit

ES:BX = puffer mutató

 

Szektor írás:

 

Int 013H

AH = 3

DL = meghajtó azonosító

DH = fejszám

CH = sávszám        ; 8bit +2 lásd az előző részben

CL = szektorszám   ; 6bit

ES:BX = puffer mutató

 

Az es:bx mutatja azt a szegmentált memóriacímet ahova, illetve ahonnan történik az írás/olvasás.

 

Például olvassuk be az első winchester (080H) MasterBootRecordját. Vagyis a 0. fej 0. sáv 1. szektorát.

 

mov ah, 02

mov dx, 0080h        ; dh = 0, dl = 80H

mov cx, 1            ; ch = 0, cl = 1

les   bx, puffer

int   013h

 

Így a pufferbe kerül az 512byte-os MBR.

 

Az előző részben már utaltam arra hogy létezik egy ún. extended read/write rutin is.

 

Olvasás

 

Int 013H

 

AH = 42h

DL = meghajtószám

DS:SI = “disk address packet”-re mutató pointer

 

Visszatérési érték:

 

CF = 0 ha sikeres volt

AH = 00h

CF = 1 ha hiba történt

AH = hibakód

 

A “disk address packet” egy rekord, amiben további paramétereket kell megadnunk.

 

Offset

Méret

Leírás

00

Byte

A packet mérete ami 16byte.

01

Byte

Ez egy fentartott byte, értéke: 0.

02

Word

Ahány szektort olvasni akarunk.

04

Dword

A cím ahova olvasni akarjuk. Szegmens+offset.

08

Qword

Az abszolút szektorszám amit ill. ahonnan olvasni akarunk 64biten de ebből csak 32bitet használunk.

 

 

Ehhez definiálhatunk egy struktúrát:

 

tpacket struc

  psize                      db  16       

  reserved                   db  0        

  number_of_blocks           dw  1        

  buffer_ofs                 dw  07c00H

  buffer_seg                 dw  0

  abssec_lo                  dd  ?

  absec_hi                   dd  0

tpacket ends

 

packet tpacket <>

 

Olvassuk be ezzel a módszerrel az MBR-t vagyis a 0. szektort a 00:07C00H címre

 

lea   si, packet                                   

mov   dword ptr [si].abssec_lo,  0       ; 0. szektor. Abszolút szektorszámmal megadva

mov   ah, 042H

mov   dl, 080H                           ; első meghajtó

int   013H   

 

Az írás hasonlóan történik, csak az AH regiszterben 043H-t kell megadnunk és természetesen ilyenkor a packet-ben a cím azt a címet fogja jelölni, ahova beolvasni szeretnénk az adatokat.

A carryflag vizsgálatával pedig eldönthetjük hogy sikeres volt-e az olvasás/írás.

Természetesen nem csak struktúrával oldhatjuk meg a dolgot, én például amikor visszafejtettem az eredeti MBR-emet, azt láttam hogy a packet-et a verembe rakja és a veremmutatót adja át a megszakításnak. Mivel 16bites valósmódban vagyunk, a 32bites paramétereket 2 lépésben tudjuk csak átadni.

 

 

push ds                 ; elmentjük a ds-t

push ss                 ; beállítjuk a veremszegmenst az adatszegmensre

pop ds

 

push 00                 ; a szektorszám felső 32 bitjének felső 16bitje. Mindig 0.

push 00                 ; a szektorszám felső 32 bitjének alsó 16 bitje. Mindig 0.

push 00                 ; a szektorszám  alsó  32 bitjének felső 16bitje

push 00                 ; a szektorszám  alsó  32 bitjének alsó 16bitje

push 00                 ; a puffer szegmens címe, ahova olvasunk

push 07C00H             ; a puffer offset címe, ahova olvasunk

push 01 h               ; 1 szektort olvasunk

push 16                 ; a packet méret pedig 16byte

mov ah, 042H

mov   dl, 080H          ; első meghajtó

mov si, sp              ; ds:si = ss:sp

Int 013H

 

add sp,16               ; felszabadítjuk a vermet

pop ds                  ; az elmentett adatszegmens

 

Ezzel ugyanúgy a 00:7C00 címre olvastuk be az MBR-t

 

 

Olvassuk be most az első particiónk BootSector-át. Ennek a szektornak az abszolút szektorszáma az MBR 01C6H offsetjénél található. Tehát olvassuk be az MBR-t, utána pedig olvassuk be az 1C6H-nál lévő, dword által jelölt szektort.

(Ha extended partíciónk van, akkor ott nem bootszektort, hanem egy újabb MBR-hez hasonló, 2 bejegyzésből álló partíciós táblát tartalmazó szektort fogunk találni.)

 

TurboPascallal inline assembly formájában a következőképpen néz ki a program.

 

uses crt;

 

Type TPacket=record

 psize: byte;

 reserved: byte;

 number_of_blocks: word;

 buffer: pointer ;

 sec_lo, sec_hi : longint;

end;                      {ez a 16byte-os packet}

 

Type tsector = array[0..511]of byte;  {egy szektortömb}

 

var

 i:word

 s: Tsector;

 

{ezzel a függvénnyel olvashatunk a megadott pufferba}

{a boolean visszatérési érték jelzi, hogy sikeres volt-e az olvasás}

 

Function harddisk_read_Extended(drive: byte; blocks: word; buf: pointer; Sector: longint):boolean;

var

 packet: TPacket;

 r: boolean;

Begin

 packet.psize:=16;     {feltöltjük a rekordot}

 packet.reserved:=0;

 packet.number_of_blocks:=blocks;

 packet.sec_lo:=sector;

 packet.sec_hi:=0;

 packet.buffer:=buf;

 asm

  push ds

  mov ah, $42

  mov dl, drive

  push ss

  pop  ds

  lea si, packet

  int $13

  jc  @err

  mov r, 1

  jmp @quit

@err:

  mov r, 0

@quit:

  pop ds

 end;

 harddisk_read_Extended:=r;

end;

 

 

Begin

 Clrscr;

{Beolvassuk az MBR-t}

 harddisk_read_Extended($80, 1, @s, 0);

{Beolvassuk az első partíció bootsector-át}

 harddisk_read_Extended($80, 1, @s, s[$1c6]);

{kiírjuk a képernyőre}

 for i:=0 to 519 do

  write(chr(s[i]));

End.

 

 

A beolvasott szektort természetesen nemcsak a képernyőre írhatjuk ki, hanem file-ba is menthetjük, így biztonsági másolatot készíthetünk a bootszektorokról és az MBR-ről.

 

A következő részben egy bootmanager konkrét megvalósításával fogunk foglalkozni.

 

Magyar Attila - trapflag@mailbox.hu