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ő
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.