Projekt z sieci komputerowych
prowadzący: mgr inż. Piotr Stera
Informatyka semestr 9, grupa 2, sekcja 1:
Mariola Firla
Ewa Korczyńska
Marcelina Kroczek
Gliwice 30 stycznia 1997Zadanie:
Napisać program (DOS) umożliwiający otwarcie dwóch sesji klienta dla różnych kont użytkownika tego samego servera Novell'a. Program powinien umożliwiać realizację wybranych operacji dla każdego z klientów oraz pomiędzy nimi.
Pomysły:
Stworzyć dwie maszyny wirtualne (w komputerach >= 80286). Uruchomić dwa zadania logujące użytkownika. Napisać program pracujący jak Windows, w trybie wirtualnym - uruchomić kilka procesów ( język „C”). Podzielić przestrzeń adresową kilku aplikacji.
Każde urządzenie we/wy ma w pamięci swoją przestrzeń adresową
Problem:
Tak podzielić pamięć, aby każdy użytkownik (proces) miał swoją odrębną przestrzeń adresową urządzeń we/wy.
Napisać program login od początku - zdublować proces logowania użytkownika. Adres sieciowy w Novell Netware składa się z trzech części:
adres sieci,
adres gniazdka (karty sieciowej),
nr procesu, (kanału logicznego).
Problem:
Zdublować procesy, aby ich adresy sieciowe były różne.
„Oszukać” Novell'a - podmieniać adres karty sieciowej. Jedna stacja Novell'a, ale dwóch wirtualnych klientów - w serverze jeden komputer widziany jako dwa.
Adres karty sieciowej można ustalić programowo. Podmieniać adres karty sieciowej
i mapowania dysków netx'owi. Przy logowaniu server identyfikuje użytkownika na podstawie adresu sieciowego karty.
Rozwiązanie:
Program rezydentny, który musi być ładowany przed netx'em.
Modyfikacja driver'a.
ad. 3a). Algorytm:
Logowanie użytkownika 1
login
pobranie adresu 1 (get_address)
Logowanie użytkownika 2
ustawienie nowego adresu karty adres2 ( set_address)
login
co określony czas (np.10min.) do servera wysyłane ramki od użytkownika 1, aby server wiedział, że użytkownik ten jeszcze pracuje
Przełączanie na użytkownika 1
ustawienie adresu 1 (set_address)
co określony czas do servera wysyłane ramki od użytkownika 2, aby server wiedział, że użytkownik ten jeszcze pracuje
Przełączanie na użytkownika 2
ustawienie adresu 2 (set_address)
co określony czas do servera wysyłane ramki od użytkownika 1, aby server wiedział, że użytkownik ten jeszcze pracuje
Na serverze są osobne kartoteki dla każdego użytkownika.
Na stacji roboczej: podmieniać tablice przemapowań i tablicę otwartych plików.
Hipotezy robocze:
W ramce do servera jest przesyłany uchwyt do zbioru (handler, który został przydzielony przez server po pierwszym odwołaniu się stacji do tego zbioru), a nie sieciowa ścieżka dostępu do niego (np. \\top\sys\...plik.txt).
Każdy użytkownik ma te same numery handlera i na serverze są wszystkie tablice przemapowań .
Problem:
Komunikacja między programami rezydentnymi.
ad. 3b) Ostatecznie wybrane rozwiązanie.
Program nie będzie działał prawidłowo w przypadku gdy ktoś będzie próbował skontaktować się z aktualnie nieaktywnym użytkownikiem (np. SEND). Problem ten można rozwiązać na dwa sposoby:
zrezygnować z obsługi tego typu sytuacji
ustawić kartę w tryb odbioru wszystkich krążących po sieci ramek i programowo dokonywać ich selekcji
Założenia.
Packet driver: PC/TCP version 1.09
Karta sieciowa: NE2000
Przełączanie między użytkownikami: naciśnięcie klawisza Scroll Lock
Rezygnacja z obsługi sytuacji problemowych opisanych wyżej
Uruchamianie packet drivera.
Po skompilowaniu okazało się, że packet driver nie potrafi korzystać z pliku konfiguracyjnego net.cfg. Parametry należy ustawiać w momencie wywołania. Poza tym współpracuje tylko z protokołami pakietowymi (choć nie ze wszystkimi wersjami) - ipxpdi: Novell IPX/SPX version 3.01;
Proponowana modyfikacja packet drivera.
Rezerwacja pamięci dla adresów kart i tablic mapowań (handlerów plików) przy ładowaniu się drivera
Przejęcie przerwania klawiatury (int 9h) - obsługa klawisza Scroll Lock
Przejęcie przerwania zegara (int 8h) - odliczanie czasu, co 10 min wysyłanie ramki do servera z adresem karty nieaktywnego użytkownika
Przygotowania.
Prosty program do pobierania zawartości pamięci od podanego adresu
- pampam.exe.
Program rezydentny przejmujący przerwanie klawiatury z własną obsługą reakcji na naciśnięcie klawisza Scroll Lock (reakcja: zmiana zawartości komórki pamięci - licznik).
Program rezydentny odliczający czas (1 min.)- reakcja na przerwanie zegara int8h .
Modyfikacja drivera.
Modyfikowaliśmy pliki: HEAD.ASM, TAIL.ASM i NE2000.ASM. Do wymienionych plików dopisałyśmy deklaracje potrzebnych dla nas zmiennych oraz nowe procedury. Wszystkie zmiany zaznaczane są przez łańcuch typu : ;*********************.
Ogólny opis modyfikacji:
HEAD.ASM:
definicje zmiennych: nasz_address, int9, int8, nr_uzytk, licznik
procedura obslugi klawiatury - klawiatura (zmiana adresu karty sieciowej po naciśnięciu klawisza Scroll Lock)
procedura obsługi zegara - zegar (odliczanie czasu co 1 min.- należy zmienić na 10 min.)
NE2000.ASM:
inicjalizacja drugiego adresu karty sieciowej - nasz_address
TAIL.ASM:
deklaracje zmiennych i procedur zewnętrznych zdefiniowanych w pliku head.asm
przejęcie przerwania klawiatury
przejęcie przerwania zegara
Kompilacja packet driver'a.
asemblacja:
tasm head.asm
tasm ne2000.asm
tasm tail.asm
linkowanie
tlink head ne2000 tail,ne2000/m;
zamiana pliku typu *.exe na plik typu *.com
exe2com ne2000
skasowanie pliku *.exe
del ne2000.exe
Aby skompilować packet driver należało przekopiować do jednej kartoteki następujące pliki:
ne2000.asm
defs.asm
8390.inc
8390.asm
multicrc.asm
timeout.asm
head.asm
tail.asm
chrout.asm
crlt.asm
decount.asm
digout.asm
getdig.asm
geterr.asm
getnum.asm
pkterr.asm
printnum.asm
printtea.asm
skipblk.asm
verifypi.asm
exe2com.exe
Uruchamianie packet driver'a.
Po skompilowaniu drivera "wychodziłyśmy" z Norton Commander'a i uruchamiałyśmy rezydentny program ne2000.com. Następnie sprawdzałyśmy jego lokalizację w pamięci (za pomocą mem/d/p). Kolejnym wykonywanym krokiem było uruchomienie programu hex.exe (program ten służy do translacji pliku typu *.com na kod heksadecymalny) z parametrem ne2000.com oraz ze skierowaniem wyniku do pliku pomocniczego. Za pomocą tego programu otrzymywałyśmy heksadecymalny kod programu ne2000.com. Kod ten był nam potrzebny do sprawdzenia, czy wprowadzone przez nas zmienne zmieniają wartości (czy cokolwiek działa). Następnie uruchamiałyśmy program pampam.exe, któremu jako parametry podawałyśmy: odczytany (za pomocą mem/d/p) adres (segment), liczbę 0110 jako offset oraz 500 - liczbę bajtów. Wynik również był skierowywany do pliku pomocniczego.
Uwagi:
Niestety zamierzony cel nie został osiągnięty - zadanie nie zostało rozwiązane do końca.
W chwili obecnej packet driver działa w następujący sposób:
po naciśnięciu klawisza Scroll Lock zmienia adres karty sieciowej,
po odliczeniu 1 min. zeruje licznik,
Zmiany, które należałoby zrobić w packet driverze:
dołożyć w procedurze obsługi przerwania 8h (zegar) wysyłanie ramki do servera,
zmienić odliczany czas z 1 min. na 10 min.
Obecna wersja packet drivera znajduje się w kartotece SK9 na serverze TOP, użytkownik rob7. W kartotece tej znajdują się:
NASZE:
DODATKI - kartoteka przechowująca programy pomocnicze: pampam.exe, hex.exe, zm.bat, zm1.bat itd.
PO_MODYF - kartoteka zawierająca packet driver po wprowadzonych modyfikacjach (tylko pliki potrezbne do karty ne2000)
URUCHOMI - kartoteka zawierająca zestaw plików do uruchomienia sieci
ORYGINAL:
- kartoteka zawierająca oryginalne pliki packet drivera dla karty ne2000.
Zauważyłyśmy, że przed pierwszym wywołaniem funkcji set_address są sprawdzane uchwyty do protokołów (procedura count_handles), co uniemożliwia zmianę adresu karty. Aby umożliwić zmianę adresu karty należało wyłączyć sprawdzanie ilości uchwytów do protokołów (procedura count_handles linia: 986).
Na naciśnięcie klawisza Scroll Lock następuje zamiana adresów karty (między "rom_address" a "nasz_address"). Po przełączeniu na "nasz_address" komputer może pracować tylko lokalnie pod warunkiem, że stacja posiada dysk twardy lub dyskietkę systemową (tzn. może pracować lokalnie) (dla servera wciąż widoczny jest użytkownik z oryginalnym adresem karty). Praca na komputerze jest możliwa dopiero po ustawieniu zmiennych środowiskoych (patrz dodatek Batche: zm.bat, zm1.bat) ponieważ mimo pracy w środowisku lokalnym zmienne środowiskowe wskazują na dyski sieciowe.
Pomimo zmiany adresu karty, dla server'a użytkownik widoczny jest wciąż pod oryginalnym adresem i nie następuje ponowne logowanie. Na tej podstawie można przypuszczać, że netx przechowuje adres karty sieciowej. W celu sprawdzenia naszej hipotezy wykonałyśmy dodatkowe badania:
Zmiana adresu karty przed załadowaniem netx'a do pamięci powodowała pomyślne zalogowanie się użytkownika z ustawionym adresem. Pomimo zmiany adresu karty po załadowaniu netx'a i zalogowaniu się do sieci server nadal widział stację z jej pierwotnym adresem karty, natomiast sama stacja pracowała w trybie lokalnym.
Korzystając z programu pampam.exe pobrałyśmy obszar pamięci zajmowany przez netx'a przed i po zalogowaniu się do sieci (przed: plik1+plik2, po: plik3+plik4). Następnie używając programu fc z opcjami: /l /n dokonałyśmy porównania zawartości odpowiadających sobie plików. Zauważyłyśmy, że netx przechowuje adres karty sieciowej stacji, na której zalogował się użytkownik.
W związku z tym, że netx przechowuje adres karty sieciowej stacji należałoby zlokalizować miejsce w pamięci gdzie jest on przechowywany(segment:offset netx'a + 7e1:7a4), a następnie w packet driver'rze przy zmianie adresu karty odpowiednio zmieniać zawartość tych komórek pamięci.
Dużym utrudnieniem przy realizacji projektu była częsta niedyspozycyjność servera TOP. Uniemożliwiało nam to pracę i testowanie programów w sieci pozostawiając jedynie czas na przemyślenia i nowe pomysły.
ad.4a)
Kod źródłowy programu do zrzucania zawartości pamięci pampam.c.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
unsigned atohex(char *ciag) /* funkcja przerabia łańcuch cyfr szesnastkowych na liczbę unsigned int */
{
char znak;
unsigned wynik=0;
unsigned czesc;
int i=0;
while(*ciag != '\0') {
if (i>=4) { printf("za duzo cyfr\n"); exit(1); }
znak = toupper(*ciag);
if ((znak>='0') && (znak<='9')) czesc = znak - '0';
else if ((znak>='A') && (znak<='F')) czesc = znak - 'A' + 10;
else{ printf("tylko cyfry szesnastkowe\n"); exit(1); }
wynik <<= 4;
wynik += czesc;
ciag++; i++;
}
return wynik;
}
main(int argc, char *argv[])
{
unsigned sseg, offs, pom;
int ilosc, i, znaki;
char *b_s, *b_o;
char bajt;
char linijka[8];
int licznik;
clrscr();
if (argc<2){ printf("uzycie: seg:offs ilosc\n");
printf(" ^^^^^^^^ ^^^^^\n");
printf(" HEX DEC \n");
exit(1);
}
b_s = strdup(argv[1]); /* zrób jeszcze jeden taki ciąg */
b_o = b_s;
while ((*b_o != ':') && (*b_o != '\0')) b_o++; /* znajdź dwukropek */
if (*b_o != ':'){ printf("coś nie w porządku z adresem\n"); exit(1); }
*b_o = '\0'; /* zamiast dwukropka wpisz koniec łańcucha, żeby były dwa łańcuchy: przed i po dwukropku*/
b_o++; /* omiń ten koniec */
sseg = atohex(b_s); /* patrz funkcja atohex ^^^ */
offs = atohex(b_o);
pom = offs >> 4; /* znormalizowanie - czyli odsunięcie */
sseg += pom; /* segmentu do góry, żeby offset był jak */
offs = offs & 0xf; /* najmniejszy */
ilosc = atoi(argv[2]); /* długość jako łańcuch -> int */
if (ilosc%8){ ilosc /= 8; ilosc++; ilosc*=8; } /* wydłużenie ilości do wielokrotności 8 */
znaki=8; /* żeby na początku wypisał adres */
for (i=0; i<ilosc; i++){
if (znaki==8){ printf("\n %4.4X:%4.4X ",sseg,offs); znaki=0; }
asm mov bx, sseg
asm mov es, bx
asm mov bx, offs
asm mov al, es:[bx]
asm mov bajt, al /* pobranie do al bajtu o adresie es=segment bx=offset */
linijka[znaki] = bajt; /* zapamiętanie na potrzeby wypisania w postaci ascii */
printf("%3.2X ", bajt); /* wypisanie w postaci szesnastkowej */
++offs;
if (znaki==8){ /* wypisanie całej linijki znaków ascii */
printf(" ");
/* poniżej spacji znaki kontrolne, które mogą spowodować nieoczekiwane efekty */
for(licznik=0; licznik<8; licznik++){
if (linijka[licznik] < ' ') printf(".");
else printf("%c", linijka[licznik]);
}
}
}
return 0;
}
ad4.b) Kod źródłowy programu rezydentnego z własną reakcją na klawisz Scroll Lock.
segment program
assume cs:program,ds:program
org 100h
start:
jmp instaluj
obsluga:
push ax
in al, 60h ; pobranie scanecode naciśniętego klawisza
cmp al, 46h ; czy naciśnięto Scroll Lock?
je tak
pop ax
jmp cs:dword ptr int9 ; powrót do pierwotnej obsługi przerwania int 9h
jmp kon
tak: ; naciśnięto Scroll Lock
mov word ptr cs:licznik, 7 ; wpisanie 7 do komórki pamięci : Licznik
pop ax
jmp cs:dword ptr int9 ; powrót do pierwotnej obsługi przerwania klawiatury
kon:
iret
licznik dw ?
int9 dd ?
instaluj: ; część instalacyjna
mov ah, 35h ; pobierz adres wektora przerwań
mov al, 09h ; AL - nr przerwania
int 21h ; na wyjściu jest ES:BX-adr. procedury obsługi przerwania
mov word ptr int9, bx ; zapamiętanie adresu właściwej procedury obsługi
mov word ptr int9 + 2, es
mov ah, 25h ; ustaw wektor przerwań
mov al, 09h ; nr przerwania
mov dx, offset obsluga ; DS:DX-adr. nowej procedury obsługi przerwania
int 21h
;CS-adr. segmentu przedrostka progr. PSP ,DX-adr. końca zadanej pamięci
mov dx, offset instaluj + 1
int 27h ; zakończenie programu bez usuwania go z pamięci
program ends
end start
Uwagi:
w części programu pozostającej w pamięci do zmiennych należy odwoływać się
z jawnym wykorzystaniem rejestrów segmentowych np.: cs:licznik;
ad.4c) Kod źródłowy programu rezydentnego z własną obsługą przerwania zegara - odliczanie czasu.
segment program
assume cs:program,ds:program
org 100h
start:
jmp instaluj
zegar:
push ax
inc cs:licznik ; zliczanie licznika przy każdym przerwaniu tj. co 1/18 sek
cmp cs:licznik, 1080h ; czy minęła już minuta?
je tak_zeg
pop ax
jmp cs:dword ptr int8 ; powrót do pierwotnej obsługi przerwania
jmp kon_zeg
tak_zeg: ; minuta minęła
mov word ptr cs:licznik,0 ; zerowanie licznika
pop ax
jmp cs:dword ptr int8 ; powrót do pierwotnej obsługi przerwania
kon_zeg:
iret
licznik dw ?
int8 dd ?
instaluj: ; część instalacyjna
mov ah, 35h ; pobierz adres wektora przerwań
mov al, 08h ; AL - nr przerwania
int 21h ; na wyjściu jest ES:BX-adr. procedury obsługi przerwania
mov word ptr int8, bx ; zapamiętanie adresu właściwej procedury obsługi
mov word ptr int8 + 2, es
mov ah, 25h ; ustaw wektor przerwań
mov al, 09h ; nr przerwania
mov dx, offset obsluga ; DS:DX-adr. nowej procedury obsługi przerwania
int 21h
;CS-adr. segmentu przedrostka progr. PSP ,DX-adr. końca zadanej pamięci
mov dx, offset instaluj + 1
int 27h ; zakończenie programu bez usuwania go z pamięci
program ends
end start
Dodatek:
Batche:
zm.bat:
set comspec=c:\dos\command.com
set zm=%path%
set path=c:\dos
zm1.bat:
set comspec=x:\command.com
set path=%zm%
Wprowadzone zmiany w plikach HEAD.ASM, NE2000.ASM, TAIL.ASM:
HEAD.ASM:
line 123:
public address_len, rom_address, my_address, nasz_address
line 128:
; zmienna przechowująca drugi adres dla karty sieciowej
nasz_address db MAX_ADDR_LEN dup (?)
line 202:
; zmienna do przechowywania oryginalnego adresu procedury obsługi przerwania klawiatury ; (int 9h)
public int9
int9 dd ?
; zmienna do przechowywania oryginalnego adresu procedury obsługi przerwania zegara ; (int 8h)
public int8
int8 dd ?
line 323:
; zmienna określająca nr aktywnego użytkownika: 0 lub 1
public nr_uzytk
nr_uzytk db ?
; procedura obsługi przerwania klawiatury
; reakcja na naciśnięcie klawisza Scroll Lock: przełączanie między użytkownikami
; w zależności od wartości zmiennej nr_uzytk. Przełączanie polega na zmianie adresu karty
; sieciowej, tzn. przypisanie zmiennej my_address wartości nasz_address, (gdy aktywny
; użytkownik nr 0) lub wartości rom_address (oryginalny adres karty, gdy aktywny użytkownik
; nr 1) oraz wywołanie funkcji set_address ustawiającej adres karty. Jednocześnie następuje
; aktualizacja wartości zmiennej nr_uzytk.
public klawiatura
klawiatura:
push ax
in al, 60h ; pobranie scancode'u naciśniętego klawisza
cmp al, 46h ; czy jest to klawisz Scroll Lock?
je tak
pop ax
jmp cs:dword ptr int9 ; powrót do pierwotnej procedury obsługi
jmp kon
tak: ; naciśnięto Scroll Lock
pop ax
push si
push cx
push di
push es
cmp cs:nr_uzytk, 1 ; czy aktywny użytkownik nr 1?
je pierwszy
mov cs:nr_uzytk, 1 ; przełączenie na użytkownika nr 1
mov cx,EADDR_LEN ; w cx długość adresu
push cs
pop ds ; w ds segment kodu
assume ds:nothing
mov si,offset nasz_address ; w si offset drugiego adresu karty
push cs
pop es ; w es segment kodu
assume es:code
mov di, offset my_address ; w di offset ustawianego adresu
rep movsb ; przepisanie po bajcie z ds:si do es:di(nasz_address do ; my_address)
push cs
pop ds
assume ds:code
mov si,offset my_address
mov cx,EADDR_LEN
call set_address ; parametry podawane do funkcji: cx - długość adresu
; karty, es:si - ustawiany adres karty
jc blad ; sygnalizacja błędu przez ustawienie flagi ; przeniesienia (carry), kod błędu zwracany jest w ; rejestrze dh
clc ; wyzerowanie flagi przeniesienia
jmp kon1
blad: ; wystąpił jakiś błąd przy ustawianiu adresu
push ax
push es ; sygnalizacja błędu poprzez wyświetlenie
mov ax, 0b800h ; literki E w lewym górnym rogu ekranu
mov es, ax
mov word ptr es:0, 00f45h
pop es
pop ax
mov si, offset rom_address ; przepisanie oryginalnego adresu karty
mov di, offset my_address ; do my_address
mov cx, MAX_ADDR_LEN/2
rep movsw
jmp kon1
pierwszy: ; operacje takie same jak dla użytkownika 0
mov cs:nr_uzytk,0
mov cx,EADDR_LEN
push cs
pop ds
assume ds:nothing
mov si,offset rom_address
push cs
pop es
assume es:code
mov di, offset my_address
rep movsb
push cs
pop ds
assume ds:code
mov si,offset my_address
mov cx,EADDR_LEN
call set_address
jc blad1
clc
jmp kon1
blad1:
push ax
push es
mov ax, 0b800h
mov es, ax
mov word ptr es:0,00f45h
pop es
pop ax
mov si, offset rom_address
mov di, offset my_address
mov cx, MAX_ADDR_LEN/2
rep movsw
kon1:
pop es
pop di
pop cx
pop si
jmp cs:dword ptr int9 ; powrót do pierwotnej procedury obsługi przerwania
kon:
iret
public licznik
licznik dw ? ; licznik do zliczania czasu
; procedura obsługi przerwania zegara.
; Poprzez inkrementację zmiennej licznik odliczany jest czas ( na razie 1minuta). Odliczanie
; to w założeniach ma posłużyć do wysyłania np. co 10 min ramki do servera z adresem ; karty nieaktywnego aktualnie użytkownika, aby server ciągle widział obu użytkowników.
public zegar ; procedura obsługi przerwania zegara
zegar:
push ax
inc cs:licznik ; inkrementacja licznika co impuls
cmp cs:licznik, 1080h ; czy minęła minuta?
je tak_zeg
pop ax
jmp cs:dword ptr int8 ; powrót do pierwotnej procedury obsługi
jmp kon_zeg
tak_zeg: ; czas minął
mov word ptr cs:licznik, 0 ; zerowanie licznika
; tu należy umieścić przesyłanie ramki od nieaktywnego użytkownika lub
; inny sposób informowania servera o aktywnym drugim użytkowniku
pop ax
jmp cs:dword ptr int8 ; powrót do pierwotnej procedury obsługi przerwania
kon_zeg:
iret
NE2000.ASM:
line 316:
; inicjalizacja drugiego adresu karty sieciowej - zmienna nasz_address = 00 00 20 12 33 21
mov byte ptr cs:nasz_address, 00h
mov byte ptr cs:nasz_address+1, 00h
mov byte ptr cs:nasz_address+2, 20h
mov byte ptr cs:nasz_address+3, 12h
mov byte ptr cs:nasz_address+4, 33h
mov byte ptr cs:nasz_address+5, 21h
TAIL.ASM:
; deklaracje zmiennych i procedur zewnętrznych
line 41:
extrn nasz_addres : byte
line 116:
extrn int9 : dword, int8 : dword
line 124:
extrn klawiatura : near
extrn zegar : near
extrn licznik : word
extrn nr_uzytk : byte
; w części inicjującej driver dopisałyśmy przejęcie obsługi przerwania klawiatury i zegara
; oraz inicjalizacja zmiennych: licznik i nr_uzytk.
line 585:
; przejęcie przerwania klawiatury int 9h
; zapamiętanie oryginalnego adresu procedury obsługi w zmiennej int9.
; Klawiatura- nowa procedura obsługi.
mov ah, 35h ; pobierz adres wektora przerwań
mov al, 09h ; nr przerwania
int 21h ; na wyjściu jest ES:BX-adres procedury obsługi przerwania
mov word ptr int9, bx ; zapamiętanie adresu oryginalnej procedury obsługi
mov word ptr int9 + 2, es
mov ah, 25h ; ustaw wektor przerwań
mov ah, 09h ; nr przerwania
mov dx, offset klawiatura ; DS:DX-adr. nowej proceduty obsługi przerwania
int 21h
mov cs:nr_uzytk, 0 ; inicjalizacja aktywnego użytkownika - 0
; przejęcie obsługi przerwania zegara int 8h. Zapamiętanie oryginalnego adresu
; procedury obsługi w zmiennej int8. Zegar- nowa procedura obsługi.
mov ah, 35h ; pobierz adres. wektora przerwań
mov al, 08h ; nr przerwania
int 21h ; na wyjściu jest ES:BX-adres procedury obsługi przerw.
mov word ptr int8, bx ; zapamiętanie adresu oryginalnej procedury obsługi
mov word ptr int8 + 2, es
mov licznik, 0h ; inicjalizacja licznika czasu
mov ah, 25h ; ustaw wektor przerwań
mov al, 08h ; nr przerwania
mov dx, offset zegar ; DS:DX-adr. nowej procedura obsługi przerwania
int 21h
Z powodu dopisania niektórych fragmentów kodu niektóre skoki do procedur okazały się za długie - konieczne było dopisanie również skoków pośrednich, aby ciągłość kodu została zachowana:
head.asm:
np. line 315:
our_isr_error1:
jmp our_isr_error
f_bad_command1:
jmp f_bad_command
w odwołaniach do powyższych skoków zmieniona została nazwa ( przez dopisanie 1 na
końcu).