                MINI KURS PISANIA PROGRAMW TSR W ASEMBLERZE

3. USUWANIE REZYDENTA Z PAMICI I JAKIE S Z TYM ZWIZANE PROBLEMY

     W  poprzednim  odcinku  dowiedzielimy si, jak napisa prosty sekundnik
instalowany  rezydentnie  w  pamici.  Cay problem w tym, e po jednorazowym
zainstalowaniu  takiego TSRa zabiera on nam kawaek cennej pamici, a gdy ju
znudz  nam  si  cyferki  wci  widoczne na ekranie - pozostaje tylko reset
komputera.  Przysza  pora  na  poznanie  kolejnej  techniki,  ktr bdziemy
stosowa,  a  mianowicie sposb na rozinstalowanie rezydenta, czyli powrt do
stanu sprzed zainstalowania.

     Na  pocztku naley si zastanowi - co tak waciwie musimy zrobi, aby
nasz  komputer dziaa tak, jakbymy nigdy TSRa nie uruchamiali. Po pierwsze:
naley   sprawdzi,  czy  w  ogle  nasz  rezydent  jest  obecny  w  pamici.
Najprociej   sprawdzi  wektor  przerwania,  ktre  on  przechwyci  podczas
instalacji  (czyli  w  przypadku  sekundnika bdzie to przerwanie 8), a potem
upewni  si,  e pod podanym adresem jest obecny nasz TSR. W tym celu moemy
po   prostu  porwna  offset  (przesunicie  w  segmencie)  pocztku  naszej
procedury  z  offsetem  podanym  nam  przez  funkcj  DOSu  czytajc  wektor
przerwania  (funkcja  35h  przerwania 21h). Jednake takie proste sprawdzenie
moe  czasem  nie  przynie  dobrych  rezultatw,  gdy  oprcz  sekundnika w
pamici  s  obecne  inne  programy  TSR  o  tych  samych  offsetach procedur
podpitych  pod  przerwanie  zegara.  Najwiksz  wiarygodno moemy uzyska
tylko  przez  sprawdzenie czego unikalnego dla naszego rezydenta. W praktyce
wystarczy porwnanie cigu znakw pod znanym adresem z naszym wzorcem - kiedy
si zgadzaj to moemy kontunuowa usuwanie TSRa z pamici komputera.

     Po  stwierdzeniu  obecnoci  TSRa  i  sprawdzeniu przechwytywanych przez
niego  przerwa  (w  przypadku  sekundnika  jest to jedno przerwanie - nr 8),
moemy  odczyta  oryginalne  wektory  tych  przerwa (wiemy bowiem, w ktrym
miejscu  w  rezydencie  s  one  "zaszyte")  i  przywrci  je  (funkcja  25h
przerwania  21h).  Pozostaje  ju tylko zwolni bloki pamici zajmowane przez
sekundnik,  wypisa  na  ekranie  komunikat o pomylnym usuniciu rezydenta i
normalnie  powrci  do  DOSu  (funkcja  4ch przerwania 21h). Oczywicie przy
instalacji  programu  warto  rwnie  sprawdzi,  czy  ju  wczeniej nie by
instalowany,  by  unikn  dwukrotnej  instalacji. Praktyczn realizacj tych
kilku  krokw  moecie  przeledzi  analizujc kod rdowy podany w dalszej
czci.

     Chwila na krtkie wyjanienie: DOS przydziela programom pami w blokach
o dugoci bdcej wielokrotnoci 16 bajtw. Poza takimi blokami danych mog
wystpi  jeszcze  bloki  z  kodem  programu  oraz bloki z otoczeniem (tam s
przechowywane  wszystkie ustawienia otoczenia programu, czyli wartoci nadane
przez  PATH,  SET,  PROMPT  itp.  -  mona  je wywietli komend SET). Kady
program  przy  uruchomieniu "otrzymuje" swj blok z kopi otoczenia DOSowego,
ktre  moe  dowolnie  modyfikowa  (np. zmieni ciek wyszukiwania PATH) i
odczytywa   (chcc  pobra  parametry  otoczenia).  Prcz  samej  zawartoci
otoczenia  na  kocu  bloku  jest  wpisywana  cieka  dostpu  i nazwa pliku
"waciciela",   czyli  programu,  do  ktrego  naley  dane  otoczenie,  np.
C:\MASM\PROGS\KURS\MOJPROG1.COM.  Jak  czyta parametry otoczenia dowiemy si
kilka  odcinkw dalej. Przy zakoczeniu programu otoczenie jest automatycznie
zwalniane  -  zmiany,  ktre  program  w  nim poczyni s tracone. Oczywicie
zostawiajc   TSRa   w  pamici  fragment  bloku  z  kodem  programu  zostaje
(wielko fragmentu zaznaczamy w rejestrze DX przy wywoaniu przerwania 27h),
natomiast reszta jest zwalniana (czyli blok jest skracany), blok z otoczeniem
rwnie  pozostaje  na  swoim miejscu. Dlatego czsto w TSRach blok otoczenia
jest  zwalniany  ju  w  czasie  instalacji,  aby zmniejszy wielko pamici
zajmowanej  przez  rezydenta. Tak te bdzie w nowej wersji sekundnika. Numer
segmentu  otoczenia (rodowiska) odczytamy ze sowa 16-bitowego umieszczonego
w  segmencie  programu  pod adresem 002ch (czyli w obszarze PSP, o tym bdzie
pniej).

     A oto przydatne informacje:

Funkcja 49h
Nazwa:          Zwalnianie pamici
Wywoanie:      AH=49h
                ES - segment, w ktrym znajduje si zwalniana pami
Powrt:         Ustawiony znacznik C : AX - kod bdu
                Nie ustawiony C : OK

     Po  wywoaniu  tej  funkcji  moemy  stwierdzi,  czy wystpi bd (np.
podalimy  numer  segmentu,  ktry  nie zaczyna nowego bloku pamici) poprzez
sprawdzenie znacznika C:

; wczeniej nadajemy rejestrom wartoci potrzebne do wywoania funkcji
  int  21h
  jc   Blad             ; skok gdy znacznik C jest ustawiony
; === nie ma bdu ===
Blad:
; === wystpi bd ===

     Pytanie  w  jaki  sposb  rozpoznamy,  czy  uytkownik chce zainstalowa
program,  czy  go  rozinstalowa  ?  Oczywicie  w  tym celu musimy sprawdzi
parametry  podane  w linii polece (czyli odrni uruchomienie: TEST.COM od:
TEST.COM /u). Dla uproszczenia przyjmijmy, e jeeli w linii polece znajdzie
si litera 'u' to naley usun TSRa z pamici.

     Znaki  podane  w  linii polece przy uruchamianiu programu s trzymane w
bloku  PSP  (ang. Program Segment Prefix), ktry w zbiorach typu COM rezyduje
na  pocztku  segmentu  z  programem  (jak  pamitamy, program zaczyna si od
adresu  100h,  wczeniej jest wanie PSP). Kolejne znaki parametrw podanych
programowi  s  zapisywane poczwszy od adresu 81h, pod adresem 80h ley bajt
zawierajcy  ilo znakw, a cay cig koczy si znakiem o kodzie 0dh (czyli
CR).  Liter  'u'  znajdziemy  porwnujc  kolejne  znaki a do znaku CR albo
wczeniejszego  napotkania 'u'. I znowu - konkretn implementacj znajdziecie
w kodzie programu.

     Przysza  pora  na  kolejne  ulepszenie  naszego  sekundnika - bdzie on
zmienia  swj  kolor  w  zalenoci  od tego, czy klawiatura bdzie w stanie
CapsLock.  Do  tego  celu przyda nam si opis zawartoci komrek danych BIOSu
pod adresami: 0040:0017h (czyli wygodniej jest napisa 0000:0417h - bdzie to
samo) i nastpnym (418h):

Adres 0:0417h
Numer bitu:     Znaczenie bitu zapalonego:
0               prawy Shift wcinity
1               lewy Shift wcinity
2               dowolny Ctrl wcinity
3               dowolny Alt wcinity
4               ScrollLock zapalony
5               NumLock zapalony
6               CapsLock zapalony
7               stan Insert

Adres 0:0418h
Numer bitu:     Znaczenie bitu zapalonego:
0               lewy Ctrl wcinity
1               lewy Alt wcinity
2               SysReq wcinity
3               stan przerwy (czyli po wciniciu Pause)
4               ScrollLock wcinity
5               NumLock wcinity
6               CapsLock wcinity
7               Insert wcinity

     Jak   widzimy,  aktualny  stan  przecznika  CapsLock  moemy  odczyta
sprawdzajc  bit  nr  6 pod adresem 0:417h, gdy bdzie zapalony to znaczy, e
klawiatura  jest  w  stanie  CapsLock (chyba nie musz tumaczy, na czym ten
stan  polega).  Sprawdzenie jednego bitu najprociej dokona instrukcj test,
ktrej  podajemy  mask  bitu  (czyli  jego  wag,  w tym przykadzie 40h), a
otrzymujemy  w  wyniku ustawienie lub wyzerowanie flagi ZF, czyli przepisanie
do  niej  zawartoci testowanego bitu (wyzerowanie ZF gdy bit by wyzerowany,
ustawienie  -  gdy  by  ustawiony).  Mona  te  instrukcj  test  wykona z
parametrem nie bdcym wag jednego bitu - wtedy zostanie logicznie wymnoony
(AND)  bajt  sprawdzany  i  podana  warto oraz odpowiednio ustawione flagi,
podobnie  jak  dziaa  instrukcja and - tylko bez zapamitywania wynikw. Dla
przypomnienia   podam   jeszcze   wagi  kolejnych  bitw,  od  0.  poczwszy:
1,2,4,8,16,32,64,128,  a w hex. to bdzie: 1,2,4,8,10h,20h,40h,80h. Popatrzmy
na fragment kodu do sprawdzenia stanu CapsLock:

  xor  ax,ax
  mov  es,ax            ; zerujemy rejestr segmentowy ES
  test byte ptr es:[417h],40h
  jz   Nie_ma_CapsLock
; CapsLock wcinity
Nie_ma_CapsLock:
; CapsLock nie wcinity

----------> Obci <----------
.model tiny
.code
.386
org 100h

Start:
  jmp  StartTutaj

; tutaj bd nasze zmienne:
staraproc dd 0
; znacznik potrzebny do sprawdzenia zainstalowania TSRa:
znacznik db 'Sekundnik, odc. 3'

NaszaProc:
  push ax
  push bx
  push di
  push es
  xor  ax,ax                 ; segment komrki ze stanem klawiatury
  mov  es,ax
  mov  bh,0ch                ; standardowy kolor jasnoczerwony do BH
  test byte ptr es:[417h],40h; sprawdzamy, czy wczony jest CapsLock
  jnz  CapsOn                ; skok gdy CapsLock wcinity
  mov  bh,1                  ; kolor niebieski - CapsLock wyczony
CapsOn:
  mov  ax,0b800h
  mov  es,ax
  xor  di,di
  xor  al,al
  out  70h,al
  jmp  $+2
  in   al,71h
  mov  bl,al
  and  bl,0fh
  add  bl,'0'
  shr  al,4
  add  al,'0'
  mov  ah,bh                 ; adujemy do AH wczeniej ustalony kolor
  stosw                      ; i rzucamy na ekran pierwsz cyfr
  mov  al,bl
  stosw                      ; potem drug
  pop  es
  pop  di
  pop  bx
  pop  ax
  jmp  dword ptr cs:[staraproc]        ; skok do oryginalnej procedury

; koniec czci rezydentnej

StartTutaj:
  mov  ah,9                  ; 09h: wydruk nagwka na ekran
  mov  dx,offset Logo
  int  21h
  mov  si,81h                ; pocztek cigu parametrw
  cld
Petla:
  lodsb                      ; wczytanie do AL jednego znaku z DS:SI, SI=SI+1
  cmp  al,'u'                ; moe to jest 'u' ?
  je   Rozinstaluj
  cmp  al,'U'                ; a moe due 'U' ?
  je   Rozinstaluj
  cmp  al,0dh                ; moe kod ENTERa (CR) ?
  je   Instaluj
  jmp  Petla                 ; skok gdy nic nie trafimy

Rozinstaluj:
  mov  ax,3508h              ; 35h: pobranie wektora przerwania
  int  21h
  cmp  bx,offset NaszaProc   ; sprawdzamy, czy si zgadzaj offsety
  jne  NieMa
  mov  si,offset znacznik    ; adres lokalnego znacznika do DS:SI
  mov  di,si                 ; i znacznika sprawdzanego do ES:DI
  mov  cx,17                 ; dugo znacznika w bajtach
  cld
  repe cmpsb                 ; sprawdzamy a do rnicego si bajtu
  jnz  NieMa                 ; skok gdy si nie zgadzaj znaczniki
; Teraz ju nie ma przeciwwskaza do rozinstalowania TSRa
  mov  dx,word ptr es:[staraproc]      ; czytamy oryginalny wektor
  mov  ax,word ptr es:[staraproc +2]   ; z bloku TSRa
  mov  ds,ax
  mov  ax,2508h              ; 25h: ustawienie wektora przerwania
  int  21h
  mov  ah,49h                ; 49h: zwolnienie bloku pamici z TSRem
  int  21h                   ; w ES mamy segment TSRa
  mov  ax,cs
  mov  ds,ax                 ; przywracamy do DS segment naszego programu
  mov  ah,9                  ; 09h: wydruk napisu na ekran
  mov  dx,offset Uninst
  int  21h                   ; drukujemy komunikat o pomylym usuniciu TSRa
  mov  ax,4c02h              ; 4ch: powrt do DOSu, w AL kod bdu
  int  21h

NieMa:
  mov  ah,9                  ; 09h: wydruk napisu na ekran
  mov  dx,offset Brak
  int  21h
  mov  ax,4c04h              ; 4ch: powrt do DOSu, w AL kod bdu
  int  21h

Instaluj:
  mov  ax,word ptr ds:[2ch]  ; numer segmentu rodowiska odczytamy z PSP,
  mov  es,ax                 ; wrzucimy do ES
  mov  ah,49h                ; 49h: zwolnienie bloku pamici
  int  21h
  mov  ax,3508h              ; 35h: pobranie wektora przerwania
  int  21h                   ; wynik wpad do ES:BX
  mov  word ptr cs:[staraproc],bx      ; trzeba jeszcze go gdzies zapamietac
  mov  word ptr cs:[staraproc +2],es
  mov  ax,2508h              ; 25h: ustawienie wektora przerwania
  mov  dx,offset NaszaProc   ; DS:DX - wektor naszej procedury
  int  21h
  mov  ah,9                  ; 09h: wydruk napisu na ekran
  mov  dx,offset Napis
  int  21h
  mov  dx,offset StartTutaj  ; do DX wpisujemy adres pierwszego bajtu,
  int  27h                   ; ktry ma by zwolniony, wczeniejsze
                             ; zostaj w pamici na stae

Logo   db 'Sekundnik 1996.',13,10
       db '     parametr /u - usunicie programu z pamici',13,10,'$'
Napis  db 'Program zainstalowany w pamici.',13,10,'$'
Brak   db 'Program nie by wczeniej instalowany w pamici.',13,10,'$'
Uninst db 'Program usunity z pamici.',13,10,'$'

end Start
----------> Obci <----------

     W  zalenoci  od stanu CapsLock ustawiamy odpowiednio kolor wpisywanych
na  ekran znakw - niech to bdzie jasnoczerwony dla CapsLock wczonego oraz
niebieski  dla CapsLock nie aktywnego. Waciwie nie pozostaje ju nic innego
jak tylko poczyta listing. Co zrobi, gdy program jest w pamici, ale zosta
po  nim zainstalowany inny rezydent oraz jak wykry tak sytuacj dowiemy si
w  nastpnym  odcinku  (przy  okazji poznamy bardzo uyteczne przerwanie 2fh,
zwane przez znawcw tematu Multiplex Interrupt).
