Instytut Teleinformatyki i Automatyki
LABORATORIUM
SYSTEMÓW WBUDOWANYCH
Sprawozdanie z ćwiczenia laboratoryjnego nr 2
TEMAT:
Tryby pracy procesorów firmy Intel
Prowadzący ćwiczenia:
dr inż. Artur Arciuch
mgr inż. Waldemar Szylberg
WSTĘP TEORETYCZNY
Zasadniczo istnieją 4 tryby pracy procesora 386+:
•
tryb rzeczywisty (real mode)
•
tryb chroniony (protected mode)
•
tryb wirtualny V86 - kombinacja 2 powyższych
•
ryb nierzeczywisty (tzw. unreal mode - procesor pracuje w RM, ale można używać adresowania 32-
bitowego; to jest raczej sztuczka programistyczna)
Każdy procesor z rodziny x86 po rozpoczęciu pracy działa w trybie rzeczywistym. W takim trybie procesor
"widzi" tylko pierwszy megabajt RAM'u i dopiero system operacyjny (typu Windows lub Linux) przełącza
go w protected mode podczas bootowania. W dodatku pamięć w RM jest podzielona na segmenty po 64kB
co np. bardzo utrudnia używanie w programach tablic o rozmiarach przekraczających ten limit.
Tryb chroniony stwarza możliwość użycia naprawdę dużej ilości pamięci (do 4 GB na 386, w
przeciwieństwie do dotychczasowego 1 MB). Nie trzeba już używać powolnych EMS i XMS by dostać się
do pamięci rozszerzonej. Ponieważ rozmiar segmentu nie jest ograniczony do 64kB, można w praktyce
wyeliminować rejestry segmentowe i operować w tzw. trybie flat - jest to ważne w przypadku kiedy
potrzebujemy dużej prędkości działania programu, DS jest zajęty a my nie chcemy prefixowac ES'em,
FS'em itd. Inne zastosowanie: operacje na buforach ekranowych przy dużych rozdzielczościach i/lub dużej
liczbie kolorów, które to bufory wymagają więcej niż 64kB pamięci.
W trybie chronionym wszystkie przerwania BIOS lub DOS'a, których używaliśmy, przykładowo, do
obsługi plików, staja się bezużyteczne bo nie mogą działać w Protected Mode (oczywiście można to obejść
poprzez chwilowe wychodzenie z trybu chronionego do trybu rzeczywistego na czas wykonywania
przerwania,
ale
nie
jest
to
już
takie
łatwe).
Nie można także beztrosko używać samomodyfikujacego się kodu - czytanie lub zapis w segmencie
wykonywalnym
spowoduje
wygenerowanie
wyjątku
GP.
Wprowadzenie mechanizmów ochrony pamięci wymagało podjęcia specjalnych środków. Każdy segment
(kod, dane, stos) opisywany jest przez tzw. deskryptor. Zadaniem deskryptora jest określenie BAZY
SEGMENTU (jego fizycznego adresu w pamięci, np. dla bufora VGA adres bazowy wynosi 0A0000h),
LIMITU (rozmiaru segmentu - może wynosić od 1B do 4GB) oraz jego TYPU/FLAG (czy segment zawiera
dane,
kod,
etc.)
Technicznie rzecz biorąc deskryptor jest to 8-bajtowa struktura danych, która rezyduje gdzieś w pamięci
operacyjnej i ma następujący format:
Znaczenie
kolejnych
bajtów
jest
takie:
0,
1
-
młodsze
słowo
długości
segmentu
(limitu)
2,
3
-
młodsze
słowo
adresu
bazowego
segmentu
4
-
młodszy
bajt
starszego
słowa
adresu
bazowego
5
-
flagi
segmentu
6
-
starszy
półbajt
limitu
i
tzw.
flagi
dostępu
7
-
starszy
bajt
starszego
słowa
adresu
bazowego
Rozmiar segmentu w protected mode może być dowolny (a wiec nie tylko 64kB, ale także każda inna
wielkość od 1B do 4GB). Jak wynika z opisu limit w deskryptorze jest to liczba 20-bitowa (8 + 8 + 4) co
daje maksymalnie 1048576 czyli 1MB.
Adres bazowy to 32-bitowa liczba wyznaczająca początek segmentu w pamięci. Zazwyczaj pisząc typowy
DOS'owy extender bazę możemy wyznaczyć poprzez pomnożenie przez 16 numeru segmentu, w którym
znajduje się nasz kod 32-bitowy. Wartość ta będzie dla nas bardzo ważna jeśli będziemy chcieli np. dobrać
się do pamięci ekranu.
Pojawia się pytanie: skąd procesor wie, gdzie w pamięci znajduje się dany deskryptor? Postanowiono
grupować deskryptory w tablice tzn. kolejno następujące po sobie deskryptory.
Tablica ta zawiera 3 deskryptory: tzw. Null Descriptor, deskryptor segmentu kodu oraz deskryptor
segmentu danych. Ten pierwszy pojawia się tylko w tablicach GDT i zawsze zawiera same zera.
Wyróżniamy 3 typy tablic: GDT (Globalna Tablica Deskryptorów), LDT (Lokalna Tablica Deskryptorów;
używana przez pojedynczy proces w systemie) oraz IDT (Tablica Deskryptorów Przerwań).
Procesor musi wiedzieć, gdzie takie tablice się znajdują i dlatego dysponuje specjalnymi rejestrami, które
zawierają 32-bitowy fizyczny adres danej tablicy oraz jej długość. Są 3 rejestry: GDTR (przechowuje adres
i długość GDT) oraz, analogicznie, LDTR i IDTR.
Kod programu przełączający procesor w tryb protected:
Comment |
Program przełączający w tryb protected
|
.386p
CR EQU 0DH
LF EQU 0AH
;-------------------------------------------------------------------------
; globalna tablica deskryptorów
segment_GDT SEGMENT use16
dq 0 ; poz. 0 - deskryptor zerowy (nieużywany)
dq 0 ; poz. 1 - selektor 0008H
dq 0 ; poz. 2 - selektor 0010H - segment 'nowe_dane'
dq 0 ; poz. 3 - selektor 0018H
dq 0 ; poz. 4 - selektor 0020H
dq 0 ; poz. 5 - selektor 0028H
dq 0 ; poz. 6 - selektor 0030H
dq 0 ; poz. 7 - selektor 0038H
dq 0 ; poz. 8 - selektor 0040H
dq 0 ; poz. 9 - selektor 0048H
dq 0 ; poz.10 - selektor 0050H
dq 0 ; poz.11 - selektor 0050H
dq 0 ; poz.12 - selektor 0050H
dq 0 ; poz.13 - selektor 0050H
dq 0 ; poz.13 - selektor 0050H
segment_GDT_end LABEL byte
segment_GDT ENDS
;-------------------------------------------------------------------
; tablica deskryptorów przerwań
segment_IDT SEGMENT use16
; Tablica zawiera furtki prowadzące do procedur obsługi przerwa¤
; i wyjątków o numerach 0 - 127. Pola 'offset' w kolejnych furtkach
; zawierać będą liczby 0, 7, 14, 21, itd.
xpom=0
REPT 128
dw xpom ; offset
dw 6 SHL 3 ; selektor
db 0 ; licznik
db 10000110B ; bajt dostępu
dw 0 ; rezerwa
xpom=xpom+7
ENDM
segment_IDT_end LABEL byte
segment_IDT ENDS
;-------------------------------------------------------------------------
; segment danych dla trybu chronionego - segment ten wskazywany jest przez
; selektor 2 * 8 = 0010H
nowe_dane SEGMENT use16
kom4 db 'Procesor pracuje w trybie chronionym '
db ' - wciśnięcie dowolnego klawisza spowoduje wyjście'
db
' - naciśniecie ESC spowoduje zakończenie programu',0
kom5 db 'Nierozpoznane polecenie', 0
txt_czas db 'czas',13,0
bufor_klaw db 128 dup (?) ; bufor klawiatury
indeks_klaw dw 0
indeks_zeg dw
0
ekran_x db 0 ; wskaźnik nr kolumny do zapisu na ekranie
ekran_y db 0 ; wskaźnik nr wiersza do zapisu na ekranie
; tablica do przekodowania kodów pozycji na kody ASCII
pozycja
dw 160*12+80
x
dw 1
y
dw 1
tabl_przekA db 0, 1BH, '1234567890-=',08H, 09H ; kody 0 - 15
db 'qwertyuiop[]', 0DH, 0, 'as' ; kody 16 - 31
db 'dfghjkl;''`',0,'\zxcv' ; kody 32 - 47
db 'bnm,./',0,'*',0,' ',0 ; kody 48 - ...
nowe_dane_end LABEL byte
nowe_dane ENDS
;-------------------------------------------------------------------------
nowy_stos SEGMENT use16 ; stos dla trybu chronionego
pstos dw 2048 dup (?)
nowy_stos_end LABEL byte
nowy_stos ENDS
;---------------------------------------------------------------------------
stos_RM SEGMENT use16 stack ; stos dla trybu rzeczywistego
dw 256 dup (?)
stos_RM ENDS
;---------------------------------------------------------------------------
ekran SEGMENT use16 at 0B800H ; segment imitujący pamięć ekranu
db 4000 dup (?)
ekran_end LABEL byte
ekran ENDS
;---------------------------------------------------------------------------
rozkazy SEGMENT use16 ; rozkazy programu
; obszary 48-bitowe potrzebne do ładowania rejestrów GDTR oraz IDTR
zaw_GDTR dp 0
zaw_IDTR dp 0
rm_idt LABEL qword ; wskaźnik do tabl. wekt. przerwań (tryb rzecz.)
dw 03FFH ; wielkość tablicy IDT
dd 0
czy_koniec db 0
komunikat1 db 'Wciśnij dowolny klawisz aby przełączyć w Protected Mode',CR, LF, '$'
komunikat2 db 'Real Mode', CR, LF, '$'
komunikat3
db 'Zakończono program',CR,LF,'$'
zadania
dw zy1,zy2,zy3
komunikat1z db 'Zadanie1 w RealMode',CR,LF,'$'
komunikat2z db 'Zadanie2 w RealMode',CR,LF,'$'
komunikat3z
db 'Zadanie3 w RealMode',CR,LF,'$'
;----------------------------------------------------------------------
; kod wykonywany ponownie w trybie rzeczywistym bezpośrednio przed
; zakończeniem wykonywania programu
ASSUME cs:rozkazy
ptt3:
lidt cs:rm_idt ; podanie adresu tabl. wektorów przerwań
; dla trybu rzeczywistego
mov ax, SEG stos_RM ; tworzenie stosu dla trybu rzecz.
mov ss, ax
mov sp, 80H
sti
call czysc_ekran
push cs
pop ds
mov dx, OFFSET komunikat2
mov ah, 09H
int 21H ; wyświetlenie komunikatu
mov al,byte ptr [czy_koniec]
cmp
al,0
je
pocz;
pelny_koniec:
mov dx, OFFSET komunikat3
mov ah, 09H
int 21H
mov ax,4C00H ; zakończenie wykonywania programu
int 21H
;----------------------------------------------------------------------
; kod wykonywany w trybie rzeczywistym bezpośrednio po uruchomieniu programu
pocz: nop
mov
al,34h
out
43h,al
mov
al,0ffh
out
40h,al
mov
al,0ffh
out
40h,al
; Wyświetlanie komunikatów o przeznaczeniu programu i oczekiwanie
; na potwierdzenie dalszego wykonywania programu
call czysc_ekran
jmp cd_przyg
; czyszczenie ekranu - przewiniecie okna o zero wierszy
czysc_ekran PROC near
mov ah, 06 ; przewiniecie okna
mov al, 0 ; zero wierszy
mov bh, 07 ; atrybut
mov ch, 0 ; współrzędne okna
mov cl, 0 ; lewy górny róg
mov dh, 24 ; prawy dolny róg
mov dl, 79
int 10H
mov ah, 2 ; ustawienie kursora w górnym lewym rogu ekranu
mov dl, 0
mov dh, 0
mov bh, 0
int 10H
ret
czysc_ekran ENDP
zy1:
mov dx, OFFSET komunikat1z
mov ah, 09H
int 21H
ret
zy2:
mov dx, OFFSET komunikat2z
mov ah, 09H
int 21H
ret
zy3:
mov dx, OFFSET komunikat3z
mov ah, 09H
int 21H
ret
cd_przyg:
push cs
pop ds
dalej_RM:
call [zadania]
call
[zadania+2]
call
[zadania+4]
mov dx, OFFSET komunikat1
mov ah, 09H
int 21H ; wyświetlenie komunikatu
mov ah, 07H ; oczekiwanie na naciśniecie klawisza
int 21H
cmp al,27
je pelny_koniec; naciśnięto Esc
call czysc_ekran;
; tworzenie deskryptorów w globalnej tablicy przerwa¤ (na razie wszystkie
; pola w deskryptorach zawierają zera)
; we wszystkich deskryptorach bajt 6 (bity G, D, 0, AVL, rozmiar 19 - 16)
; pozostawiany jest bez zmian (zawiera zero)
; ASSUME ds:segment_GDT
mov ax, SEG segment_GDT
mov ds, ax ; ładowanie rejestru DS
; tworzenie deskryptora na pozycji 2 w GDT - deskryptor ten opisuje
; segment 'nowe_dane'
mov bx, 2 * 8 ; offset w segmencie segment_GDT
mov word PTR ds:[bx], OFFSET nowe_dane_end - 1 ; rozmiar segmentu
mov ax, SEG nowe_dane
movzx eax, ax ; zerowanie starszej części EAX
shl eax, 4 ; w EAX adres bazowy segmentu
mov ds:[bx]+2,ax ; adres bazowy 15 - 0
rol eax, 16 ; zamiana połówek EAX
mov ds:[bx]+4, al ; adres bazowy 23 - 16
mov ds:[bx]+7, ah ; adres bazowy 31 - 24
mov byte PTR ds:[bx]+5, 10010010B ; bajt dostępu
; tworzenie deskryptora na pozycji 3 w GDT - deskryptor ten opisuje
; segment 'ekran'
mov bx, 3 * 8 ; offset w segmencie segment_GDT
mov word PTR ds:[bx], OFFSET ekran_end - 1 ; rozmiar segmentu
mov ax, SEG ekran
movzx eax, ax ; zerowanie starszej części EAX
shl eax, 4 ; w EAX adres bazowy segmentu
mov ds:[bx]+2,ax ; adres bazowy 15 - 0
rol eax, 16 ; zamiana połówek EAX
mov ds:[bx]+4, al ; adres bazowy 23 - 16
mov ds:[bx]+7, ah ; adres bazowy 31 - 24
mov byte PTR ds:[bx]+5,10010010B ; bajt dostępu
; tworzenie deskryptora na pozycji 6 w GDT - deskryptor ten opisuje
; segment 'obsl_int'
mov bx, 6 * 8 ; offset w segmencie segment_GDT
mov word PTR ds:[bx], OFFSET obsl_int_end - 1 ; rozmiar segmentu
mov ax, SEG obsl_int
movzx eax, ax ; zerowanie starszej części EAX
shl eax, 4 ; w EAX adres bazowy segmentu
mov ds:[bx]+2,ax ; adres bazowy 15 - 0
rol eax, 16 ; zamiana połówek EAX
mov ds:[bx]+4, al ; adres bazowy 23 - 16
mov ds:[bx]+7, ah ; adres bazowy 31 - 24
mov byte PTR ds:[bx]+5,10011010B ; bajt dostępu
; tworzenie deskryptora na pozycji 7 w GDT
mov bx, 7 * 8 ; offset w segmencie segment_GDT
mov word PTR ds:[bx], OFFSET nowy_stos_end - 1 ; rozmiar segmentu
mov ax, SEG nowy_stos
movzx eax, ax ; zerowanie starszej części EAX
shl eax, 4 ; w EAX adres bazowy segmentu
mov ds:[bx]+2,ax ; adres bazowy 15 - 0
rol eax, 16 ; zamiana połówek EAX
mov ds:[bx]+4, al ; adres bazowy 23 - 16
mov ds:[bx]+7, ah ; adres bazowy 31 - 24
mov byte PTR ds:[bx]+5,10010010B ; bajt dostępu
; tworzenie deskryptora na pozycji 8 w GDT
mov bx, 8 * 8 ; offset w segmencie segment_GDT
mov word PTR ds:[bx], OFFSET rozkazy_end - 1 ; rozmiar segmentu
mov ax, SEG rozkazy
movzx eax, ax ; zerowanie starszej części EAX
shl eax, 4 ; w EAX adres bazowy segmentu
mov ds:[bx]+2,ax ; adres bazowy 15 - 0
rol eax, 16 ; zamiana połówek EAX
mov ds:[bx]+4, al ; adres bazowy 23 - 16
mov ds:[bx]+7, ah ; adres bazowy 31 - 24
mov byte PTR ds:[bx]+5,10011010B ; bajt dostępu
; tworzenie deskryptora na pozycji 9 w GDT - deskryptor używany jako
; atrapa przy przejsciu z trybu chronionego do rzeczywistego (w tym
; przypadku adres bazowy w deskryptorze nie ma żadnego znaczenia)
mov bx, 9 * 8 ; offset w segmencie segment_GDT
mov word PTR ds:[bx],0FFFFH ; wymagany rozmiar segmentu
; bajt dostępu musi opisywać segment danych (fikcyjny), w którym:
; P=1, ED=0, W=1
mov byte PTR ds:[bx]+5,10010010B ; bajt dostępu
; tworzenie deskryptora na pozycji 10 w GDT - deskryptor ten opisuje
; segment kodu 'roz_zak', który jest wykonywany bezpośrednio przed
; przejściem do trybu rzeczywistego (pole "wielkosc" = FFFFH)
mov bx, 10 * 8 ; offset w segmencie segment_GDT
mov word PTR ds:[bx], 0FFFFH ; rozmiar segmentu
mov ax, SEG roz_zak
movzx eax, ax ; zerowanie starszej części EAX
shl eax, 4 ; w EAX adres bazowy segmentu
mov ds:[bx]+2,ax ; adres bazowy 15 - 0
rol eax, 16 ; zamiana połówek EAX
mov ds:[bx]+4, al ; adres bazowy 23 - 16
mov ds:[bx]+7, ah ; adres bazowy 31 - 24
mov byte PTR ds:[bx]+5,10011010B ; bajt dostępu
; tworzenie deskryptora na pozycji 11 w GDT
mov bx, 8 * 11 ; offset w segmencie segment_GDT
mov word PTR ds:[bx], OFFSET zad1_end- 1 ; rozmiar segmentu
mov ax, SEG zad1
movzx eax, ax ; zerowanie starszej części EAX
shl eax, 4 ; w EAX adres bazowy segmentu
mov ds:[bx]+2,ax ; adres bazowy 15 - 0
rol eax, 16 ; zamiana połówek EAX
mov ds:[bx]+4, al ; adres bazowy 23 - 16
mov ds:[bx]+7, ah ; adres bazowy 31 - 24
mov byte PTR ds:[bx]+5,10011010B ; bajt dostępu
; tworzenie deskryptora na pozycji 11 w GDT
mov bx, 8 * 12 ; offset w segmencie segment_GDT
mov word PTR ds:[bx], OFFSET zad2_end- 1 ; rozmiar segmentu
mov ax, SEG zad2
movzx eax, ax ; zerowanie starszej części EAX
shl eax, 4 ; w EAX adres bazowy segmentu
mov ds:[bx]+2,ax ; adres bazowy 15 - 0
rol eax, 16 ; zamiana połówek EAX
mov ds:[bx]+4, al ; adres bazowy 23 - 16
mov ds:[bx]+7, ah ; adres bazowy 31 - 24
mov byte PTR ds:[bx]+5,10011010B ; bajt dostępu
; tworzenie deskryptora na pozycji 11 w GDT
mov bx, 8 * 13 ; offset w segmencie segment_GDT
mov word PTR ds:[bx], OFFSET zad3_end- 1 ; rozmiar segmentu
mov ax, SEG zad3
movzx eax, ax ; zerowanie starszej części EAX
shl eax, 4 ; w EAX adres bazowy segmentu
mov ds:[bx]+2,ax ; adres bazowy 15 - 0
rol eax, 16 ; zamiana połówek EAX
mov ds:[bx]+4, al ; adres bazowy 23 - 16
mov ds:[bx]+7, ah ; adres bazowy 31 - 24
mov byte PTR ds:[bx]+5,10011010B ; bajt dostępu
; tworzenie deskryptora na pozycji 11 w GDT
mov bx, 8 * 14 ; offset w segmencie segment_GDT
mov word PTR ds:[bx], OFFSET shed_end- 1 ; rozmiar segmentu
mov ax, SEG shed
movzx eax, ax ; zerowanie starszej części EAX
shl eax, 4 ; w EAX adres bazowy segmentu
mov ds:[bx]+2,ax ; adres bazowy 15 - 0
rol eax, 16 ; zamiana połówek EAX
mov ds:[bx]+4, al ; adres bazowy 23 - 16
mov ds:[bx]+7, ah ; adres bazowy 31 - 24
mov byte PTR ds:[bx]+5,10011010B ; bajt dostępu
; przygotowanie do wykonania rozkazu LGDT (ładowanie rejestru GDTR)
mov ax, OFFSET segment_GDT_end ; rozmiar tablicy GDT
mov word PTR cs:zaw_GDTR+0, ax
mov ax, SEG segment_GDT ; adres (segmentowy) globalnej
; tablicy deskryptorów
movzx eax, ax ; zerowanie starszej części EAX
shl eax, 4 ; w EAX adres bazowy segmentu
mov dword PTR cs:zaw_GDTR+2, eax
; przygotowanie do wykonania rozkazu LIDT (ładowanie rejestru IDTR)
mov ax, OFFSET segment_IDT_end ; rozmiar tablicy GDT
mov word PTR cs:zaw_IDTR+0, ax
mov ax, SEG segment_IDT ; adres (segmentowy) tablicy
; deskryptorów przerwań
movzx eax, ax ; zerowanie starszej części EAX
shl eax, 4 ; w EAX adres bazowy segmentu
mov dword PTR cs:zaw_IDTR+2, eax
cli ; zablokowanie przyjmowania przerwań
lgdt cs:zaw_GDTR ; ładowanie rejestru GDTR
lidt cs:zaw_IDTR ; ładowanie rejestru IDTR
; przelaczenie do trybu chronionego
mov eax, CR0
or eax, 1
mov CR0, eax
jmp next ; oczyszczenie kolejki rozkazów
; oczekujących na wykonanie
next: nop
; Skok daleki do następnej instrukcji - instrukcja ta powoduje zapisanie
; także rejestru CS w taki sposób, że selektor 0040H (czyli 8 * 8)
; wpisany do CS wskazuje na deskryptor w tablicy GDT, opisujący
; niniejszy segment. Zatem będzie dalej wykonywany kod z tego samego
; segmentu, ale rejestr CS zawiera teraz selektor, a nie adres segmentu.
; Rozkaz skoku dalekiego jest kodowany bajtowo ponieważ
; w asemblerze brak potrzebnego trybu adresowania 'jmp far PTR ca1'
DB 0EAH
DW tryb_PM
dw 8 * 8 ; selektor wskazujący na deskryptor
; segmentu 'rozkazy'
tryb_PM: nop
;-------------------------------------------------------------------------
; przeprogramowanie układu 8259, tak by przerwanie z zegara (nr 8 w trybie
; rzeczywistym) było związane z nr 32, przerwanie z klawiatury (nr 9)
; - z nr 33, itd.
call przestaw_8259
; inicjalizacja stosu - segment stosu dla trybu chronionego
; opisany jest przez deskryptor 7
mov ax, 7 * 8
mov ss, ax
mov sp, 1000
; inicjalizacja rejestrow DS, ES, FS, GS - wpisanie selektora wskazującego na
; segment 'nowe_dane'
mov ax, 2 * 8
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
; call zeruj_bufor_klaw ; zerowanie bufora klawiatury
sti ; włączenie przyjmowania przerwań
; wyswietlenie komunikatu "Procesor pracuje w trybie chronionym"
mov bx, OFFSET kom4
call wyswietl
;-----------------------------------------------------------------------
; Główna pętla przyjmowania zleceń od użytkownika w trybie chronionym
; sprawdź, czy w buforze klawiatury jest kod Enter (0DH) lub Esc (1BH)
czytaj_od_nowa:
mov ax, 2 * 8
mov ds, ax
; mov dx, 0 ; używany do sterowania wyświetlaniem
DB 0EAH
DW str1
dw 8 * 14
db 0
klaw14:
mov cx, ds:indeks_klaw
jcxz klaw14 ; skok, gdy pusty bufor
mov
ds:indeks_klaw,0
cmp
cx,001Bh
jne
klaw14b;
push ds
mov
ax,8*8
mov
ds,ax
mov
al,1
mov byte ptr[czy_koniec],al
pop ds
klaw14b:
; przygotowanie do powrotu do trybu rzeczywistego - skok daleki
; do segmentu kodu (kodowany bajtowo, ponieważ
; w asemblerze brak potrzebnego trybu adresowania 'jmp far PTR przelacz_do_RM'
DB 0EAH
DW przelacz_do_RM
dw 10 * 8 ; nr pozycji deskryptora wskazującego
; segment rozkazowy
; przeprogramowanie układu 8259, tak by przerwanie z zegara (nr 8 w trybie
; rzeczywistym) było związane z nr 32, przerwanie z klawiatury (nr 9)
; - z nr 33, itd.
przestaw_8259 PROC
mov al,11H
out 20H,al ; ładowanie ICW1 (d4=1 - znacznik
; wskazujący, ze programujemy ICW1
; bit d0=1 - znacznik ,ze wystąpi ICW4
mov al,32
out 21H,al ; ustawienie bazowego wektora przerwań
; (ustawienie ICW2)
mov al,4
out 21H,al ; ICW3 - d2=1 - tryb niebuforowany, 8259 master
mov al,1
out 21H,al ; ICW4 - d0=1 - potwierdzenie ICW2 jako wektora
; przerwań
ret
przestaw_8259 ENDP
;--------------------------------------------------------------------------
; wyswietlanie tekstu na ekranie - tekst zawarty jest w segmencie danych
; dla trybu chronionego (selektor 0010H), a offset podany jest w BX
; tekst wyswietlany jest w wierszu wskazanym przez zmienna ekran_y
; ekran_x db 0 ; wskaźnik nr kolumny do zapisu na ekranie
; ekran_y db 0 ; wskaźnik nr wiersza do zapisu na ekranie
wyswietl PROC
; selektor 0010H (2 * 8) wskazuje deskryptor segmentu danych dla trybu
; chronionego ('nowe_dane')
push ds
push es
mov ax, 2 * 8
mov ds, ax
mov ax, 3 * 8 ; selektor pamięci ekranu
mov es,ax
mov al, 160
mul byte PTR ds:ekran_y ; w AX adres ekranu do zapisu
mov di, ax
mov ah,7 ; atrybut wyświetlania
ptl_kom: mov al,ds:[bx] ; pobranie kolejnego znaku komunikatu
or al, al
jz koniec_wysw ; bajt zerowy wskazuje koniec tekstu
mov es:[di],ax ; przesłanie znaku do pamięci ekranu
inc bx ; inkrementacja BX
inc di ; inkrementacja DI
inc di ; inkrementacja DI
jmp ptl_kom
koniec_wysw:
mov al, ds:ekran_y
inc al
cmp al, 23
jae przesun_ekran
mov ds:ekran_y, al
zak_wysw:
pop es
pop ds
ret
; przesuwanie calego ekranu o jeden wiersz w gore
przesun_ekran:
dec al
mov ds:ekran_y, al
mov ax, 3 * 8 ; selektor pamięci ekranu
mov ds, ax
mov es, ax
mov cx, 2000 - 240
mov si, 160
mov di, 0
cld
rep movsw
jmp zak_wysw
wyswietl ENDP
rozkazy_end LABEL near
rozkazy ENDS
;----------------------------------------------------------------------
roz_zak SEGMENT use16
ASSUME cs:roz_zak
; rozkazy zawarte w tym segmencie wykonywane są bezpośrednio przed
; przejściem z trybu chronionego do trybu rzeczywistego
przelacz_do_RM: nop
; przywrócenie tradycyjnych numerów przerwa¤
cli ; wyłączenie przyjmowania przerwa¤
mov al,11H
out 20H,al
mov al,8
out 21H,al
mov al,4
out 21H,al
mov al,1
out 21H,al ; ładowanie ICW4
mov al,0BCH
out 21H,al
; przed przejściem do trybu rzeczywistego rejestry segmentowe powinny
; zawierać selektory wskazujące fikcyjny segment danych (zob. opis
; deskryptora 10)
mov ax, 9 * 8 ; deskryptor na pozycji nr 9 wskazuje
; fikcyjny segment danych
mov ds,ax
mov es,ax
mov ss,ax
mov fs, ax
mov gs, ax
; zerowanie bitu PG w CR0
mov eax, CR0
and eax, 7FFFFFFFH
mov CR0, eax
; zerowanie rejestru CR3
mov eax, 0
mov CR3, eax
; zerowanie bitu PE w rejestrze CR0 (włączenie trybu rzeczywistego)
mov eax, CR0
and eax,0FFFFFFFEH
mov CR0, eax
jmp far PTR ptt3
roz_zak ENDS
;-----------------------------------------------------------------------
obsl_int SEGMENT use16
ASSUME cs:obsl_int
; Każdemu przerwaniu odpowiadają 3 rozkazy zajmujące łącznie 7 bajtów.
; Pierwszy z tych rozkazów zapamiętuje rejestr CX na stosie, zaś następny
; wpisuje do CX nr przerwania lub wyjątku, co pozwala, w dalszej części
; procedury obsługi, zidentyfikował przyczynę przerwania i ewentualnie
; podjął działania właściwe dla zaistniałego zdarzenia.
xpom=0
REPT 128
push cx ; nr przerwania lub wyjątku
mov cx,xpom
jmp proc_obsl
xpom=xpom+1
ENDM
ORG $+128 ; wymusza by nie występowały JMP SHORT
proc_obsl: sti
push ds
push es
push ax
push bx
push dx
push si
cmp cx,33 ; czy przerwanie z klawiatury
je klawisze
sti
jmp
przeskocz_klaw
; obsluga przerwania z klawiatury
klawisze:
in al,60H ; odczyt kodu pozycji klawisza
xor ah,ah ; zerowanie rejestru AH
push ax ; przechowanie rejestru AX
in al,61H
or al,82H
out 61H,al
and al,7FH
out 61H,al
pop ax ; odtworzenie rejestru AX
cmp al, 57
ja przeskocz_klaw ; nie sa obsługiwane klawisze o kodach
; pozycji > 55
mov bx, 2 * 8 ; selektor do segmentu 'nowe_dane'
mov ds, bx
mov si, OFFSET tabl_przekA
mov bl, al
xor bh, bh
mov al, ds:[si+bx]
klaw2:
; dopisanie znaku do bufora
cli
; mov bx, OFFSET bufor_klaw
; add bx, ds:indeks_klaw
; mov ds:[bx], al
dalej:
mov word PTR ds:indeks_klaw,ax
mov
bx,3*8
mov
es,bx
mov bx,ds:pozycja
mov
es:[bx],al
jmp przeskocz_klaw
przeskocz_klaw:
mov al, 20H
out 20H, al ; end of interrupt (OCW2)
pop si
pop dx
pop bx
pop ax
pop es
pop ds
pop cx
iret
obsl_int_end LABEL near
obsl_int ENDS
shed SEGMENT use16
ASSUME cs:shed
z1 db 0
z2 db 0
z3 db 0
nz db 0
nzb db 0
str1:
DB 0EAH
DW s
dw 8 *11 ; selektor wskazujący na deskryptor
za2:
DB 0EAH
DW ss1
dw 8 *12 ; selektor wskazujący na deskryptor
za3:
DB 0EAH
DW sss
dw 8 *13 ; selektor wskazujący na deskryptor
konza:
DB 0EAH
DW klaw14
dw 8 *8 ; selektor wskazujący na deskryptor
; segmentu 'rozkazy'
shed_end label near
shed ENDS
zad1 SEGMENT use16
ASSUME cs:zad1
s:
push ds;
mov ax,8*3
mov ds,ax
mov al,'a'
mov bx,160*3
mov byte ptr ds:[bx],al
pop ds
DB 0EAH
DW za2
dw 8 * 14 ; selektor wskazujący na deskryptor
; segmentu 'rozkazy'
zad1_end label near
zad1 ENDS
zad2 SEGMENT use16
ASSUME cs:zad2
ss1:
push ds;
mov ax,8*3
mov ds,ax
mov al,'b'
mov bx,160*4+2
mov byte ptr ds:[bx],al
pop ds
DB 0EAH
DW za3
dw 8 * 14 ; selektor wskazujący na deskryptor
; segmentu 'rozkazy'
zad2_end label near
zad2 ENDS
zad3 SEGMENT use16
ASSUME cs:zad3
sss:
push ds;
mov ax,8*3
mov ds,ax
mov al,'c'
mov bx,160*5+4
mov byte ptr ds:[bx],al
pop ds
DB 0EAH
DW konza
dw 8 * 14 ; selektor wskazujący na deskryptor
; segmentu 'rozkazy'
zad3_end label near
zad3 ENDS
END pocz