                MINI KURS PISANIA PROGRAMW TSR W ASEMBLERZE

5. WYWOYWANIE PRZERWA DOSOWYCH W CZASIE PRACY TSR'A

     Pity   odcinek   kursu   pisania   TSRw  bdzie  powicony  problemom
wywoywania  przerwa  DOSa w trakcie dziaania rezydenta i sposobom radzenia
sobie  z  tymi  trudnociami.  Ot zacznijmy od tego, e w naszym rezydencie
(nazwijmy  go  roboczo:  "Grabber")  przechwycilimy  przerwanie klawiatury i
chcemy,  aby  si  uaktywni  po  naciniciu  przez  uytkownika  kombinacji
klawiszy  LewyShift+LewyCtrl+Delete,  po  czym  zapisa  do zbioru w katalogu
C:\TEMP zawarto ekranu trybu graficznego 13h. Jest to tryb o rozdzielczoci
320x200  w  256  kolorach,  w ktrym od pocztku segmentu A000h zapisane s w
kolejnych bajtach kolory punktw najwyszej linii ekranu (poczynajc od lewej
strony), od adresu A000h:320 kolory punktw w drugiej linii itd. W ten sposb
otrzymujemy  320x200  =  64000  bajtw do zapisania w zbiorze. Do tego naley
doliczy  768  bajtw na palet kolorw (768=3*256, mamy 256 kolorw, kady o
skadowych:  czerwonej,  zielonej  i  niebieskiej). Aby nasze zbiory nie byy
"oderwane"  od  rzeczywistego wiata, bdziemy je zapisywa w formacie .BMP -
dokadajc  na  pocztku  zbioru  stay  nagwek  (poniewa  za kadym razem
zapisujemy  ekran  o  tej  samej  wielkoci i liczbie kolorw) oraz zgodnie z
konwencj   zapisu  plikw  .BMP  -  bdziemy  zapisywali  kolejne  linie  od
najniszej  do  najwyszej (czyli w kolejnoci odwrotnej, ni ich pooenie w
pamici   ekranu).   Kolejne   pliki  bd  otrzymyway  nazwy  OBRAZ000.BMP,
OBRAZ001.BMP i tak dalej.

     Tutaj  zaczynaj  si nasze problemy - nie moemy tak poprostu bezkarnie
utworzy  nowego  pliku  w  katalogu C:\TEMP, zapisa do niego nasze dane, po
czym  go  zamkn.  W momencie nacinicia kombinacji klawiszy uaktywniajcej
naszego  rezydenta  bdzie przecie wykonywany inny program, ktry moe w tej
chwili  sam  zapisywa jakie dane. Wtedy DOSowi zrobi si "mtlik w gowie",
co  doprowadzi  w najlepszym przypadku do zawieszenia komputera, a moemy te
uszkodzi  system  plikw  lub  dokona  TSRem  czego  bardziej okrutnego. I
wanie  o  to  chodzi,  aby  omin moment, w ktrym inny program korzysta z
usug  dosowych.  Z pomoc w tej sytuacji przyjd nam mechanizmy udostpniane
przez  sam  system operacyjny, a mianowicie flaga INDOS - jeden bajt pamici,
ktry  informuje  nas, czy wanie w tej chwili jest wykonywana jaka funkcja
DOSa.  Adres  flagi  INDOS  moemy  uzyska poprzez odwoanie do nastpujcej
funkcji przerwania 21h:

Nazwa:          Pytanie o adres sygnalizatora pracy systemu
Wywoanie:      AH=34h
Powrt:         ES:BX - adres sygnalizatora pracy systemu
Opis:           Funkcja    zwraca    adres   sygnalizatora   pracy   systemu.
                Sygnalizator  ten  jest ustawiony (rny od zera), gdy system
                wykonuje  jak  czynno,  ktrej  nie  naley mu przerywa.
                Sygnalizator  ten  jest  czsto  uywany  przez programy TSR,
                ktre  sprawdzaj,  czy  mog si uaktywni. Sygnalizator ten
                jest  rwnie  ustawiony  podczas  czekania  przez  system na
                nacinicie   klawisza.   W  takim  wypadku  jest  wywoywane
                przerwanie  28h,  ktre  TSR moe przechwyci i rwnie w ten
                sposb si uaktywnia.

     Przy okazji poznalimy kolejny wany aspekt programowania TSRw - pomimo
e  jest  wykonywane  przerwanie DOSa, ktre oczekuje na wcinicie klawisza,
nie  robic  prcz tego nic poytecznego, flaga INDOS jest zapalona. Ten fakt
jednake  moemy  wykry  poprzez  sprawdzenie, czy DOS wywouje w tym czasie
przerwanie  28h  (tzw. przerwanie Idle). Robimy to poprzez przechwycenie tego
przerwania  i  podstawienia  w  jego  miejsce swojej wasnej procedury. Kiedy
uytkownik nacinie odpowiedni kombinacj klawiszy, sprawdzamy, czy DOS jest
w  tej  chwili  wolny  -  flaga  INDOS=0. W przeciwnym wypadku musimy dokona
sprawdzenia,  czy jest wywoywane przerwanie 28h (w naszej procedurze obsugi
tego  przerwania  zapalamy odpowiedni flag aktywnoci). Jeeli nie jest ono
wywoywane,  a  DOS  jest  zajty - nie moemy w tej chwili nic zrobi. Wtedy
mamy   kilka  moliwoci  rozwizania  tego  problemu,  jak  np.  przepisanie
zawartoci   ekranu   (wraz   z   palet)  do  innego  bloku  pamici,  ktry
zarezerwowalimy  przy  instalacji,  a przy najbliszej okazji zapisanie tego
bloku  na dysk (tutaj okazao by si pomocne przechwycenie rwnie przerwania
zegara  -  INT  08h  -  ktre  bdzie  nam dostarczao t "najblisz okazj"
okoo  18  razy  na  sekund). Jednake kto by chcia uywa TSRa, ktry przy
instalacji   zabiera   nam   ponad  64000  bajtw  cennej  pamici  ?  Drugim
rozwizaniem  jest zaalokowanie poredniego bloku w pamici XMS lub EMS - ale
na to przyjdzie czas w kolejnych odcinkach tego cyklu. My w naszym rezydencie
wykorzystamy  trzeci  moliwo  -  po prostu nic nie zrobimy, wydajc tylko
krtki  dwik  z  gonika informujcy o naszej bezradnoci. I jeszcze jedna
uwaga  - gdy DOS czeka na nacinicie klawisza wywoujc co chwil przerwanie
28h,  a my z tego skorzystamy, nie moemy po uaktywnieniu rezydenta korzysta
z przerwa dosowych o numerach od 00h do 0Ch.

     No to mamy ju oglny zarys dziaania naszego TSRa: w procedurze obsugi
przerwania   klawiatury   sprawdzamy,   czy  nacinito  kombinacj  klawiszy
LShift+LCtrl+Delete,  a  gdy  miao  to  miejsce,  przekazujemy do sterownika
klawiatury potwierdzenie odebrania znaku i w odblokowujemy kontroler przerwa
(jest  to  szczegowo  opisane  w  4. odcinku tego kursu), po czym ustawiamy
nasz  wewntrzn  flag  aktywnoci i wczamy przerwania instrukcj: "sti".
Kiedy  teraz  uytkownik  znowu nacinie t kombinacj klawiszy, a my jeszcze
nie skoczylimy obsugi poprzedniego nacinicia (czyli gdy nasza wewntrzna
flaga  aktywnoci  jest  zapalona) - wtedy po prostu wychodzimy z przerwania.
Dalej  naley  sprawdzi  flag  INDOS  -  gdy jest zapalona to dajemy sygna
dwikowy informujcy o naszej bezradnoci i rwnie wychodzimy z przerwania,
nie  zapominajc o zgaszeniu naszej wewntrznej flagi aktywnoci. W kocu gdy
wszystko  si  powiodo  -  przystpujemy  do  rzeczy.  Tworzymy nowy zbir w
katalogu  C:\TEMP  (lub innym, kady moe wstawi sobie w kod rdowy to, co
chce), zapisujemy do tego zbioru stay nagwek, czytamy palet kolorw karty
VGA  do  naszego  obszaru  roboczego o wielkoci 768 bajtw, zapisujemy j do
pliku,  dalej  nagrywamy  kolejne  linie  obrazu  poczynajc od najniszej (o
adresie  0A000h:0F8C0h)  a  do najwyszej (o adresie 0A000h:0), zmniejszajc
offset nagrywanego bloku pamici za kadym razem o 320 bajtw (dugo jednej
linii).  Potem  tylko  zamykamy  plik,  gasimy  wewntrzn flag aktywnoci i
powracamy  z  przerwania.  Cay  kod tej operacji wstawimy w naszego gotowego
rezydenta, korzystajcego z przerwania 2Fh (Multiplex Interrupt), opisywanego
w  poprzednim  odcinku cyklu, pomijajc tylko chwilowo nam niepotrzebn cz
suc  do  dezaktywowania  TSRa  bez  usuwania  go z pamici. Nasz rezydent
bdzie  "wraliwy"  na numer procesu 91h podawany przy wywoywaniu przerwania
2Fh.

     Teraz  czas  na  kilka  zagadnie nie dotyczcych bezporednio programw
rezydentnych, ale bardzo nam przydatnych. Ot musimy wiedzie po pierwsze, w
jaki  sposb  sprawdzi,  czy  karta graficzna jest w trybie 13h. Moemy tego
dokona wywoujc bezporednio podfunkcj 0Fh przerwania video - INT 10h:

Nazwa:          Pytanie o aktualny tryb wywietlania
Wywoanie:      AH=0Fh
Powrt:         AL - tryb pracy
                AH - liczba znakw w wierszu
                BH - numer aktywnej strony

     Jednake  moemy  odczyta  numer  trybu  rwnie  bez uycia przerwa -
szybciej  i  bezpieczniej  (ten  sam  problem,  co z przerwaniem dosowym - co
bdzie,  gdy  akurat  w tym momencie gwny program odwoa si do przerwania
video  ?  Rozwizanie  problemu  byoby  bardziej  skomplikowane), odczytujc
bezporednio  odpowiedni  warto z obszaru zmiennych BIOSu, zawarto bajtu
spod adresu 0040h:0049h (czyli 0:0449h) rwnie jest numerem aktualnego trybu
pracy  karty  graficznej.  Kolejne  zagadnienie  to odczytanie palety kolorw
karty  VGA. W przestrzeni adresowej wejcia/wyjcia (I/O) caego komputera s
wydzielone  porty,  z  ktrych korzysta karta VGA. Maj one adresy od 3C0h do
3DFh.  Aby  odczyta skadowe RGB jednego koloru, naley do portu 3C7h wysa
bajt  z numerem koloru (0..255), a nastpnie z portu 3C9h odczyta po kolei 3
bajty  ze  skadowymi:  czerwon,  zielon  i  niebiesk. Licznik koloru jest
automatycznie  zwikszany  o  1,  moemy  potem  od  razu  odczyta  skadowe
kolejnego  koloru,  ju bez wpisywania jego numeru do portu 3C7h. Najszybciej
mona   odczyta   ca   palet  kolorw  pod  adres  w  ES:DI  przy  pomocy
nastpujcych instrukcji:

  xor  al,al       ; AL=0
  mov  dx,3c7h
  out  dx,al
  mov  dl,0c9h
  mov  cx,768      ; odczytujemy 256*3 = 768 bajtw
  cld
  rep  insb        ; z portu DX odczytaj kolejno CX bajtw i umie pod ES:DI

     Na  nasze  nieszczcie  paleta jest zapisywana w zbiorach .BMP w bardzo
przedziwny  sposb  -  kady kolor zajmuje w niej nie 3, ale 4 bajty - i to w
kolejnoci:  niebieski, zielony, czerwony, a 4. bajt jest rwny zero. Do tego
jeszcze karta VGA zwraca nam skadowe kolorw z zakresu 0..63, a w pliku .BMP
s  zapisywane  skadowe z zakresu 0..255. Musimy to wszystko uwzgldni przy
budowie  naszego  rezydenta  -  konkretne  rozwizanie  znajdziecie  w kodzie
rdowym doczonym do tego odcinka.

     Aby  przy  bezradnoci naszego rezydenta (kiedy nie moemy wykorzystywa
przerwa  DOSa)  wyda  sygna  dwikowy  nie  za  dugi  i  nie  za krtki,
posikujemy  si  odczytem  zmiennej  BIOSa  zawierajc ilo taktw zegara,
zwikszanej  w  kadym  przerwaniu  zegarowym (INT 08h), czyli co okoo 55 ms
(18.2  raza  na sekund). Po prostu wczymy dwik, odczytamy jej zawarto,
poczekamy,  a  ulegnie  zmianie  o  np.  2, po czym wyczymy dwik. Sposb
prosty i skuteczny. Naley tylko pamita o wczeniu przerwa ju wczeniej,
aby  zostaa  wykonana  procedura  obsugi  zegara zwikszajca licznik. No i
najwaniejsze:  licznik  mieci  si  w pamici od adresu 0:046Ch i zajmuje 4
bajty,  w  kolejnoci  od  najmodszego  do  najstarszego. W naszym przypadku
wystarczy  sprawdzi,  czy  si  zmieni  ten  najmniej  znaczcy  (czyli pod
adresem, ktry podaem wyej).

     Operacje  na  plikach  wykonujemy  korzystajc  z  usug  dobrze ju nam
znanego   przerwania   DOSu   -  21h.  Przy  otwieraniu  lub  tworzeniu  plik
identyfikowany  jest przez nazw zapisan w ASCIIZ, natomiast przy nastpnych
odwoaniach  do  ju  otwartego  zbioru  (przy  zapisywaniu  do niego danych,
zamykaniu go) wykorzystujemy tzw. file handle (uchwyt, dojcie), czyli liczb
16-bitow okrelajc nam w sposb jednoznaczny, z jakim wczeniej otwieranym
plikiem  mamy  do  czynienia.  Oto  opisy  funkcji  dosowych,  ktre  nam si
przydadz:

Nazwa:          Tworzenie dojcia
Wywoanie:      AH=3Ch
                DS:DX - adres acucha w kodzie ASCIIZ zawierajcego nazw
                        pliku
                CX - atrybuty pliku
Powrt:         Ustawiony znacznik C: AX - kod bdu
                Nie ustawiony C: AX - numer dojcia
Opis:           Funkcja tworzy plik o podanej nazwie, rwnoczenie definiujc
                do dojcie z uprawnieniami do czytania i pisania w pliku.
                Nowy plik ma zerow dugo i atrybuty przekazane w rejestrze
                CX. Jeli plik o podanej nazwie ju instnieje to zostaje
                zwolniona pami dyskowa mu przydzielona, nadana dugo 0,
                ustalone nowe atrybuty i przyporzdkowane dojcie z uprawn.
                do czytania i pisania.

     Wyjanienia  wymaga  zawarto  rejestru CX ustawianego przed wywoaniem
funkcji  3Ch.  Atrybuty  pliku  s reprezentowane przez kolejne bity w dolnej
powce rejestru CX (czyli w CL), grn powk (CH) wypeniamy zerami:

bit:   7 6 5 4 3 2 1 0      r - Read Only
       - - a d v s h r      h - Hidden
                            s - System
                            v - Volume ID
                            d - Directory
                            a - archive

     Wida,  e przy pomocy tej funkcji moemy rwnie utworzy nowy katalog,
zapalajc  w  CL  czwarty bit, jednake jeeli ju istnieje taki katalog, nie
ulegnie  automatycznemu  skasowaniu,  inaczej  ni  to si dzieje w przypadku
plikw.  W  naszym  rezydencie  nowo  tworzonym plikom bdziemy nadawa tylko
atrybut  Archive - czyli do rejestru CX wpisywa warto 0020h. Po utworzeniu
pliku  bdziemy  zwiksza  jego  numer  -  3  ostatnie  cyfry nazwy stanowi
licznik. Zapisu danych do otwartego pliku dokonujemy przy pomocy funkcji 40h:

Nazwa:          Pisanie przez dojcie
Wywoanie:      AH=40h
                BX - numer dojcia
                CX - liczba bajtw do zapisania
                DS:DX - adres bufora
Powrt:         Ustawiony znacznik C: AX - kod bdu
                Nie ustawiony C: AX - liczba zapisanych bajtw
Opis:           Funkcja   zapisuje   do  pliku  lub  urzdzenia  zwizanego z
                dojciem,  ktrego numer jest przekazany w rejestrze BX bajty
                znajdujce si w buforze, ktrego adres zawiera DS:DX. Liczba
                bajtw  do  zapisania  jest  przekazywana  w rejestrze CX. Po
                zapisie wewntrzny wskanik pozycjipliku jest przesuwany tak,
                aby  wskazywa  na bajt nastpny po ostatnio zapisanym. W ten
                sposb   moliwe   jest   sekwencyjne  zapisywanie  w  pliku.
                Wywoanie  tej  funkcji  z  zawartoci  CX  rwn 0 powoduje
                zmian  wielkoci  pliku  na  tak,  jak  aktualnie wskazuje
                wskanik pozycji.

Nazwa:          Zamykanie dojcia
Wywoanie:      AH=3Eh
                BX - numer dojcia
Powrt:         Ustawiony znacznik C: AX - kod bdu
                Nie ustawiony C: OK.
Opis:           Funkcja zamyka dojcie o numerze przekazanym w AX i czyci
                wszystkie bufory zwizane z plikiem.

     No  to  waciwie  posiadamy  ju  ca  wiedz  potrzebn  do napisania
rezydenta,  ktrym  bdziemy  zrzucali  ekran karty VGA do pliku .BMP, naley
tylko  doda,  e  ta  metoda bdzie dawaa dobre rezultaty tylko w przypadku
programw korzystajcych z "czystego" trybu 13h - 320x200 w 256 kolorach, bez
adnych "upiksze" w stylu Xmode (podnoszenie rozdzielczoci na standardowej
karcie  VGA  poprzez  zmian trybu adresowania), z czego intensywnie korzysta
wikszo programw demonstracyjnych i cz gier. Nasze eksperymenty rwnie
nie  powiod si, gdy program przechwytuje przerwanie klawiatury i nie zwraca
sterowanie  do  oryginalnej  procedury  obsugi.  Wtedy  moemy  zainstalowa
rezydenta  w  przerwaniu  zegara  (INT  08h)  i  tam  sprawdza, czy ostatnio
wciskanym  klawiszem by Delete, jak rwnie uaktualnia flagi stanu klawiszy
kontrolnych  na  podstawie informacji o wciniciach/puszczeniach Alt, Ctrl i
Shift.  Ale to ju bdzie tematem innego odcinka. Podobnie ma si sprawa przy
naszym  uproszczeniu  -  w  przykadowym  rezydencie nie sprawdzamy, czy jest
wywoywane  przerwanie  28h,  po stwierdzeniu zajtoci DOSu (flaga INDOS<>0)
tylko  dajemy dwik naszej bezradnoci. Mona te po prostu wykomentowa lub
usun zaznaczone w kodzie linie - flaga INDOS nie bdzie w ogle sprawdzana.
To  chyba  ju  wszystko  na  dzi,  przykadowy  program  jest  dziaajcy i
sprawdzony  tylko  dla  kilku  programw, nie dziaajca reszta zawiera si w
przypadkach opisanych powyej. Powodzenia w samodzielnym eksperymentowaniu.
