Wykład V
Współpraca systemu
operacyjnego ze sprzętem
komputerowym
Podstawy informatyki
Semestr I Transport
Semestr II Elektrotechnika
Wprowadzenie
Na tym wykładzie omówimy odrębne części systemu
komputerowego.
Ponieważ
system
operacyjny
jest
niezwykle blisko powiązany z mechanizmami wejścia-
wyjścia komputera, najpierw zajmiemy się wejściem-
wyjściem. Później omówimy strukturę magazynowania
danych.
System operacyjny musi również zapewniać poprawne
działanie systemu komputerowego. Aby programy użytkowe
nie mogły zdezorganizować pracy systemu, sprzęt powinien
mieć odpowiednie mechanizmy gwarantujące właściwe
zachowanie się całości. W dalszej części tego wykładu
omówimy
podstawową
architekturę
komputera,
umożliwiającą napisanie sprawnie działającego systemu
operacyjnego.
Działanie systemu
komputerowego
Nowoczesny, uniwersalny system komputerowy składa
się z jednostki centralnej (ang. central processor unit
- CPU) i pewnej liczby sprzętowych sterowników
urządzeń (ang. device controller) połączonych wspólną
szyną umożliwiającą kontakt ze wspólną pamięcią (rys.).
Każdy sterownik urządzenia odpowiada za określony typ
urządzenia (np. za napędy dysków, urządzenia
dźwiękowe i wyświetlacze obrazu)
Jednostka centralna i sterowniki urządzeń mogą działać
współbieżnie, rywalizując o cykle pamięci. Sterownik
pamięci ma za zadanie zapewnić uporządkowany,
synchroniczny dostęp do wspólnej pamięci.
System komputerowy
...
Program rozruchowy
Aby komputer mógł rozpocząć pracę, na przykład gdy zostaje
podłączony do zasilania lub gdy wznawia się jego działanie,
musi w nim nastąpić wykonanie jakiegoś wstępnego
programu.
Ów
wstępny
program,
nazywany
też
programem
rozruchowym (ang. bootstrap program), jest zazwyczaj
stosunkowo prosty.
Określa on stan początkowy wszelkich elementów systemu,
poczynając od rejestrów jednostki centralnej, poprzez
sterowniki urządzeń, aż po zawartość pamięci.
Program rozruchowy musi wiedzieć, jak załadować system
operacyjny i rozpocząć jego działanie. Aby wywiązać się z
tego zadania, musi on zlokalizować i wprowadzić do pamięci
jądro systemu operacyjnego.
Przerwania
System operacyjny rozpoczyna wówczas wykonanie
swojego pierwszego procesu, w rodzaju procesu init, i
zaczyna czekać na wystąpienie jakiegoś zdarzenia.
Wystąpienie zdarzenia jest na ogół sygnalizowane za
pomocą przerwania (ang. interrupt) pochodzącego od
sprzętu lub od oprogramowania.
Sprzęt może powodować przerwania w dowolnej chwili,
wysyłając sygnał do jednostki centralnej zwykle za
pomocą szyny systemowej.
Oprogramowanie może spowodować przerwanie wskutek
wykonania specjalnej operacji nazywanej wywołaniem
systemowym (ang. system call), a niekiedy -
wywołaniem monitora (ang. monitor call).
Obsługa przerwań
Istnieje wiele różnych rodzajów zdarzeń mogących powodować
przerwanie. Są to na przykład: zakończenie operacji wejścia-
wyjścia, dzielenie przez zero, niedozwolony dostęp do pamięci
lub zapotrzebowanie na pewną usługę systemu.
Każdemu takiemu przerwaniu odpowiada procedura zajmująca
się jego obsługą.
Procesor po otrzymaniu sygnału przerwania wstrzymuje
aktualnie wykonywaną pracę i natychmiast przechodzi do
ustalonego miejsca w pamięci. Miejsce to zawiera na ogół adres
startowy procedury obsługującej dane przerwanie. Następuje
wykonanie procedury obsługi przerwania, po której zakończeniu
jednostka centralna wznawia przerwane obliczenia. Przebieg
czasowy tych operacji widać na rysunku (następny slajd).
Wykres czasowy przerwań
procesu wykonującego
operację wyjścia
Obsługa przerwań -
Wspólna procedura lub wektor
przerwań
Przerwania są ważnym elementem architektury komputera.
Poszczególne
rodzaje
komputerów
mają
jednak
indywidualne mechanizmy przerwań, niemniej jednak kilka
ich funkcji jest wspólnych.
Przerwanie musi przekazywać sterowanie do procedury
obsługi przerwania. Prosty sposób spowodowania tego
polega na wywołaniu ogólnej procedury sprawdzającej
informacje opisujące przerwanie, która na tej podstawie
wywoła konkretną procedurę obsługi przerwania.
Jednak przerwania muszą być obsługiwane szybko, więc
przy założeniu, że liczba możliwych przerwań jest zadana z
góry, można zamiast takiego postępowania posłużyć się
tablicą wskaźników do procedur obsługujących przerwania.
Wektor przerwań
Procedura obsługi przerwania jest wówczas wywoływana
za pośrednictwem tej tablicy, bez potrzeby korzystania z
pośredniczącej procedury.
Tablica takich wskaźników jest z reguły przechowywana w
dolnej części pamięci (pierwszych 100 komórek lub
podobnie). Ta tablica, zwana wektorem przerwań (ang.
interrupt vector), jest indeksowana jednoznacznym
numerem urządzenia, w który jest zaopatrywane żądanie
przerwania, dzięki czemu otrzymuje się właściwy adres
procedury obsługującej przerwanie zgłoszone przez dane
urządzenie.
Nawet tak różne systemy operacyjne, jak MS-DOS i UNIX,
kierują przerwania do obsługi w opisany sposób.
Obsługa przerwania
wymaga zapamiętania
stanu bieżącego
W architekturze przerwań trzeba również uwzględniać
przechowywanie adresu przerwanego rozkazu.
W wielu starych rozwiązaniach ten adres był po prostu
przechowywany w ustalonej komórce lub w komórce
indeksowanej numerem urządzenia.
W
nowszych
konstrukcjach
adres
powrotny
jest
przechowywany na stosie systemowym.
Jeśli procedura obsługi przerwania chce zmienić stan
procesora, na przykład przez zmianę wartości rejestrów, to
musi jawnie przechować stan bieżący, a przy końcu swojego
działa musi go odtworzyć.
Po obsłużeniu przerwania następuje pobranie do licznika
rozkazów zapamiętanego adresu powrotnego i wznowienie
przerwanych obliczeń, tak jakby przerwania nie było.
Wyłączanie i włączanie
przerwań
Zwykle podczas obsługi jednego przerwania inne przerwania są
wyłączone (ang. disabled), więc każde nowe przerwanie jest
opóźniane do czasu, aż system upora się z bieżącym
przerwaniem i przerwania zostaną włączone (ang. enabled).
Jeśli nie byłoby wyłączania przerwań, to przetworzenie drugiego
przerwania - przy niedokończonej obsłudze pierwszego - mogłoby
zniszczyć (przez ponowne zapisanie) dane pierwszego przerwania
i spowodować jego utratę (ang. lost interrupt).
Doskonalsze architektury przerwań zezwalają na obsługę nowego
przerwania przed zakończeniem obsługi innego. Zazwyczaj
korzysta się w tym celu ze schematu priorytetów, w którym
poszczególnym typom żądań nadaje się priorytety według ich
względnej ważności, a związane z przerwaniami informacje są
pamiętane w osobnym miejscu dla każdego priorytetu.
Nowoczesne systemy operacyjne
są sterowane przerwaniami (ang.
interrupt driven)
Jeżeli nie ma procesów do wykonania, żadne urządzenia
wejścia-wyjścia nie wymagają obsługi i nikt z
użytkowników nie oczekuje odpowiedzi, to system
operacyjny spokojnie czeka na jakieś zdarzenie.
Zdarzenia są prawie zawsze sygnalizowane za pomocą
przerwań lub tzw. pułapek.
Pułapka (ang. trap), czyli wyjątek, jest rodzajem
przerwania generowanym przez oprogramowanie, a
powodowanym albo przez błąd (np. dzielenie przez zero
lub próba niewłaściwego dostępu do pamięci), albo
przez specjalne zamówienie pochodzące z programu
użytkownika, które wymaga obsłużenia przez system
operacyjny.
System operacyjny jest sterowany
zdarzeniami, co znajduje
odzwierciedlenie w jego ogólnej
strukturze
Po wykryciu przerwania (lub pułapki) sprzęt przekazuje
sterowanie do systemu operacyjnego.
System operacyjny w pierwszej kolejności przechowuje
bieżący stan jednostki centralnej, zapamiętując zawartość
rejestrów i licznika rozkazów.
Następnie ustala rodzaj powstałego przerwania. Może to
wymagać odpytywania (ang. polling), tj. badania stanu
wszystkich urządzeń wejścia-wyjścia w celu wykrycia tego,
które potrzebuje obsługi, albo może stanowić naturalny
wynik zadziałania wektorowego systemu przerwań.
Każdemu rodzajowi przerwania odpowiadają w systemie
operacyjnym oddzielne segmenty kodu, określające
działania, które należy podjąć w związku z przerwaniem.
Sprzętowe sterowniki
urządzeń wejścia-wyjścia
Uniwersalny system komputerowy składa się z jednostki
centralnej i pewnej liczby sprzętowych sterowników urządzeń
połączonych za pomocą wspólnej szyny.
Każdy ze sterowników urządzeń odpowiada za określony typ
urządzenia. Do niektórych rodzajów sterowników można
dołączyć więcej niż jedno urządzenie (np. do sterownika
SCSI).
Sprzętowy sterownik urządzenia zarządza pewną ilością
lokalnej pamięci buforowej i zbiorem specjalizowanych
rejestrów. Sterownik taki odpowiada za przemieszczanie
danych między urządzeniami zewnętrznymi, nad którymi
sprawuje nadzór, a swoją lokalną pamięcią buforową.
Wielkość lokalnego bufora w sterownikach urządzeń zależy
od ich rodzaju i rodzaju nadzorowanego urządzenia.
Wykonywanie operacji
wejścia-wyjścia
Aby rozpocząć operację wejścia-wyjścia, jednostka
centralna określa zawartość odpowiednich rejestrów
w sterowniku urządzenia.
Sterownik sprawdza dane w tych rejestrach, żeby
określić rodzaj mającego nastąpić działania. Jeśli
sterownik wykryje na przykład zamówienie czytania,
to rozpocznie przesyłanie danych z urządzenia do
swojego lokalnego bufora.
Po
przesłaniu
danych
sterownik
urządzenia
informuje jednostkę centralną, że skończył operację.
Aby przekazać tę wiadomość, sterownik powoduje
przerwanie.
Obsługa wejścia-wyjścia
Przedstawiona sytuacja występuje z reguły jako wynik
zamawiania przez proces użytkownika operacji wejścia-wyjścia.
Po rozpoczęciu operacji wejścia-wyjścia są możliwe dwa
scenariusze zdarzeń:
w najprostszym przypadku operacja przesyłania danych
rozpoczyna się, kończy, po czym sterowanie wraca do procesu
użytkownika; ten przypadek nazywa się synchronicznym
wejściem-wyjściem (ang. synchronous I/O).
druga możliwość - nazywana asynchronicznym wejściem-
wyjściem (ang. asynchronous I/O) - polega na oddaniu
sterowania do programu użytkownika bez czekania na
zakończenie operacji; operacja wejścia-wyjścia może być wtedy
kontynuowana wraz z innymi działaniami systemu (patrz rys.
na następnym slajdzie)
Dwa sposoby obsługi
wejścia-wyjścia
(a) synchroniczny; (b) asynchroniczny
Oczekiwanie na
zakończenie transmisji
Czekanie na zakończenie transmisji może się odbyć na jeden z dwu
sposobów:
Niektóre komputery mają specjalny rozkaz wait (czekaj), który
powoduje bezczynność procesora aż do chwili wystąpienia
następnego przerwania.
Maszyny nie mające takiego rozkazu mogą wykonywać pętlę
czekania:
Loop: jmp Loop
Ta zwięzła pętla jest po prostu powtarzana tak długo, aż nadejdzie
sygnał przerwania powodujący przekazanie sterowania do innej
części systemu operacyjnego.
W pętli tego rodzaju może powstać konieczność odpytywania
urządzeń wejścia-wyjścia, które nie powodują przerwań, lecz
określają po prostu znacznik w jednym z ich własnych rejestrów
i oczekują, że system operacyjny zauważy zmianę jego wartości.
Tego rodzaju rozwiązanie
nie jest idealne
Jeżeli jednostka centralna zawsze czeka na koniec
operacji wejścia-wyjścia, to w danej chwili tylko jedno
zamówienie wejścia-wyjścia pozostaje nie obsłużone.
Gdy zatem występuje przerwanie z wejścia-wyjścia,
wtedy
system
operacyjny
jest
dokładnie
poinformowany o tym, które urządzenie wysłało
przerwanie.
Jednak takie podejście wyklucza równoczesną
pracę kilku urządzeń, jak również wyklucza
możliwość zachodzenia na siebie w czasie
pożytecznych obliczeń i operacji wejścia-wyjścia.
Można lepiej
Lepszym rozwiązaniem jest zapoczątkowanie transmisji i
kontynuowanie innych działań systemu operacyjnego
lub programu użytkownika.
Potrzebne jest wówczas wywołanie systemowe, czyli
zamówienie odnoszące się do systemu operacyjnego,
które
w razie
potrzeby
pozwoliłoby
programowi
użytkownika zaczekać na zakończenie operacji wejścia-
wyjścia.
Jeżeli żaden z programów użytkownika nie będzie
gotowy do działania, a system operacyjny nie będzie też
miał nic innego do roboty, to znów okaże się potrzebny
rozkaz czekania lub pętla bezczynności - tak jak
poprzednio.
Tablica stanów urządzeń
(ang. device status table)
Musimy również umieć odnotowywać wiele zamówień na
operacje wejścia-wyjścia w tym samym czasie.
W tym celu system operacyjny posługuje się tablicą, której
elementy odnoszą się do poszczególnych urządzeń. Jest to
tablica stanów urządzeń.
Każdy element tej tablicy (rys. na następnym slajdzie) określa
typ urządzenia, jego adres i stan (odłączone, bezczynne, zajęte).
Jeżeli urządzenie jest zajęte z powodu przyjęcia zamówienia, to
odpowiadający mu element tablicy zawiera rodzaj zamówienia i
inne parametry.
Ponieważ inne procesy mogą składać zamówienia do tego
samego urządzenia, system operacyjny będzie utrzymywał dla
każdego urządzenia kolejkę, tj. listę, oczekujących zamówień.
Kolejki zamówień w
tablicy stanów urządzeń
Obsługa urządzeń
Urządzenie wejścia-wyjścia wysyła przerwanie, jeśli
wymaga obsługi.
Po wystąpieniu przerwania system operacyjny określa
najpierw, które urządzenie spowodowało przerwanie.
Następnie pobiera z tablicy urządzeń informacje o stanie
danego urządzenia i zmienia je, odnotowując wystąpienie
przerwania.
Zakończenie wykonywania operacji jest przez większość
urządzeń
wejścia-wyjścia
również
sygnalizowane
przerwaniem.
Jeśli są jakieś następne zamówienia oczekujące na dane
urządzenie, to system operacyjny rozpoczyna ich
realizację.
Zakończenie procedury
obsługi przerwania
Na koniec procedura obsługi przerwania urządzenia wejścia-
wyjścia zwraca sterowanie.
Jeśli na zakończenie jej działania czekał jakiś program (co
zostało odnotowane w tablicy stanów urządzeń), to można
oddać mu sterowanie.
W przeciwnym razie następuje powrót do tego, co było robione
przed przerwaniem: do wykonywania programu użytkownika
(program rozpoczął operację wejścia-wyjścia, operacja ta się
zakończyła, a program nie zaczął jeszcze na nią czekać) albo
do pętli czekania (program zapoczątkował dwie lub więcej
operacji wejścia-wyjścia i czeka na zakończenie jednej z nich,
lecz to przerwanie pochodziło od jakiejś innej).
W systemie z podziałem czasu system operacyjny mógłby
podjąć wykonywanie innego procesu gotowego do działania.
Po co stosujemy
asynchroniczną obsługę
wejścia-wyjścia ?
Główną zaletą asynchronicznego wejścia-wyjścia
jest większa wydajność systemu.
W czasie wykonywania operacji wejścia-wyjścia
jednostka centralna systemu może być użyta do
przetwarzania lub rozpoczynania operacji wejścia-
wyjścia odnoszących się do innych urządzeń.
Ponieważ operacje wejścia-wyjścia mogą być
powolne w porównaniu z szybkością procesora,
system wykorzystuje go w znacznie lepszym
stopniu.
Przykład – obsługa
terminala
Rozważmy prosty moduł obsługi (sterownik) terminalu.
Gdy ma być przeczytany jeden wiersz danych, wówczas pierwszy
napisany znak będzie przesłany d o komputera. Po jego nadejściu
urządzenie transmisji asynchronicznej (lub port), do którego jest
przyłączony terminal, wysyła sygnał przerwania do procesora.
W chwili nadejścia od terminalu sygnału przerwania procesor
będzie zapewne wykonywać jakiś rozkaz. (Jeśli procesor jest w
środku cyklu wykonywania rozkazu, to przerwanie z reguły jest
wstrzymywane do czasu zakończenia danego rozkazu). Następuje
wtedy zapamiętanie adresu rozkazu, przy którym wystąpiło
przerwanie, i przekazanie sterowania do procedury obsługi
danego urządzenia.
Procedura obsługi przerwania zapamiętuje bieżące zawartości
wszelkich rejestrów procesora, którymi będzie się posługiwać.
Przykład – obsługa
terminala
cd.
Sprawdza, czy w związku z poprzednią operacją wejścia nie
wystąpiły jakiekolwiek błędy. Potem pobiera znak od urządzenia i
zapamiętuje go w buforze.
Procedura przerwania musi także uaktualnić wskaźnik i zmienne
licznikowe bufora, aby następny znak z wejścia mógł być
zapamiętany w następnej komórce bufora.
Z kolei procedura przerwania ustawia znaczniki w pamięci,
wskazując innym częściom systemu operacyjnego, że otrzymano
nowe dane wejściowe. Inne części systemu odpowiadają za
przetwarzanie danych w buforze i przekazywanie znaków do
programu, który żąda danych wejściowych.
Następnie procedura obsługi przerwania odtwarza poprzednią
zawartość wszystkich używanych przez nią rejestrów i oddaje
sterowanie do przerwanego rozkazu.
Obsługa wolnych
urządzeń
Jeśli znaki są pisane na terminalu o wydajności np. 9600
bodów, to mogą one być akceptowane i przesyłane w
przybliżeniu co 1ms (1000μs).
Dobrze napisanej procedurze obsługi przerwania mogą
wystarczyć 2μs na wprowadzenie znaku do bufora. Z
każdego zatem tysiąca μs procesorowi pozostaje zatem
998μs na obliczenia i obsługę innych przerwań.
Na skutek tej dysproporcji przerwania asynchronicznego
wejścia-wyjścia otrzymują zwykle niski priorytet, dzięki
czemu przerwania ważniejsze mogą być obsługiwane w
pierwszej kolejności, a nawet powodować zaniechanie
obsługi bieżącego, mniej ważnego przerwania.
Obsługa szybkich
urządzeń
Natomiast szybkie urządzenia, takie jak dyski, taśmy albo sieci
komunikacyjne, mogą przesyłać informacje z szybkością zbliżoną
do szybkości pamięci operacyjnej.
Mogłoby się zatem zdarzyć, że procesor potrzebuje 2μs na obsługę
każdego przerwania, a nadchodzą one (na przykład) co 4 μs. Nie
zostaje więc wiele czasu na wykonywanie procesu.
Problem ten rozwiązuje się, umożliwiając szybkim urządzeniom
wejścia-wyjścia bezpośredni dostęp do pamięci operacyjnej
(ang. direct memory access - DMA). Po ustawieniu buforów,
wskaźników i liczników sterownik danego urządzenia przesyła
bezpośrednio cały blok danych między własnym buforem a
pamięcią - bez interwencji procesora.
Przerwanie wypada wówczas jeden raz na cały blok danych, a nie
po przesłaniu każdego znaku (lub słowa), jak to się dzieje w
przypadku powolnych urządzeń zewnętrznych.
Działanie jednostki
centralnej podczas
przesyłania z użyciem
DMA
Zasadnicze działanie jednostki centralnej pozostaje
niezmienione. Program użytkownika lub sam system
operacyjny może zażądać przesłania danych.
System operacyjny wybiera bufor (pusty wejściowy lub
pełny wyjściowy) z kolejki buforów do przesłania.
Następnie część systemu operacyjnego, zwana modułem
obsługi urządzenia (ang. device driver), ustawia
w rejestrach sterownika DMA odpowiednie adresy źródła i
miejsca przeznaczenia oraz długość transmisji.
Z kolei sterownik DMA zostaje poinstruowany, że należy
zainicjować operację wejścia-wyjścia. Gdy sterownik DMA
jest zajęty przesyłaniem danych, jednostka centralna
może wykonywać inne zadania.
DMA obciąża system
Ponieważ
pamięć
operacyjna
może
zazwyczaj przesyłać tylko jedno słowo w
danej chwili, więc sterownik DMA „kradnie”
cykle pamięci jednostce centralnej.
Ta
kradzież
cykli
może
spowalniać
działanie jednostki centralnej w trakcie
przesyłania DMA.
Po zakończeniu przesyłania sterownik DMA
wysyła jednostce centralnej przerwanie.
Współpraca z pamięcią
Programy muszą znajdować się w pamięci operacyjnej, aby mogły być
wykonywane. Pamięć operacyjna (ang. main memory) jest jedynym
wielkim obszarem pamięci dostępnym dla procesora bezpośrednio.
Tworzy ona tablicę słów lub bajtów, których liczba waha się od setek
tysięcy do setek milionów. Każde słowo ma własny adres.
Współpraca z pamięcią operacyjną odbywa się za pomocą ciągu
rozkazów load (pobierz) lub store (przechowaj) odnoszących się do
określonych adresów.
Rozkaz load powoduje pobranie słowa z pamięci operacyjnej do
wewnętrznego rejestru jednostki centralnej,
natomiast rozkaz store powoduje umieszczenie zawartości rejestru
procesora w pamięci operacyjnej
.
Oprócz jawnych pobrań i umieszczeń jednostka centralna
automatycznie pobiera z pamięci operacyjnej rozkazy do wykonania.
Cykl rozkazowy
Typowy cykl rozkazowy w systemie o architekturze von
Neumanna (patrz poprzednie wykłady) zaczyna się od
pobrania rozkazu z pamięci i przesłania go do rejestru
rozkazów (ang. instruction register).
Rozkaz jest następnie dekodowany i realizowany (może
spowodować pobranie argumentów z pamięci i umieszczenie
ich w innym rejestrze wewnętrznym).
Po wykonaniu rozkazu na argumentach jego wynik można z
powrotem przechować w pamięci.
Zauważmy, że jednostka pamięci „widzi” tylko strumień
adresów pamięci. Nie jest jej znany sposób, w jaki one
powstały (licznik rozkazów, indeksowanie, modyfikacje
pośrednie, adresy literalne itp.) ani czemu służą (rozkazy lub
dane).
Dlaczego wszystkie dane nie
są przechowywane w
pamięci operacyjnej?
W idealnych warunkach moglibyśmy sobie życzyć, aby program i
dane stale pozostawały w pamięci operacyjnej. Nie jest to
możliwe z dwu powodów:
1.
Pamięć operacyjna jest zazwyczaj za mała, aby przechowywać
na stałe wszystkie potrzebne programy i dane.
2.
Pamięć operacyjna jest tzw. pamięcią ulotną (nietrwałą; ang.
volatile storage). Traci ona swoją zawartość po odłączeniu
zasilania.
Wobec
tego
większość
systemów
komputerowych
jest
wyposażona w pamięć pomocniczą (ang. secondary storage),
która rozszerza pamięć operacyjną. Od pamięci pomocniczej
wymaga się przede wszystkim, aby mogła trwale przechowywać
duże ilości danych.
To, co przede wszystkim różni te systemy pamięci, to szybkość
działania, koszt, rozmiar i ulotność (danych).
Dyski magnetyczne
(i inne rodzaje pamięci
pomocniczej)
Najpopularniejszym urządzeniem pamięci pomocniczej jest
dysk magnetyczny umożliwiający zapamiętywanie zarówno
programów, jak i danych (oczywiście istnieje wiele innych
sposobów przechowywania danych: CD, DVD, Blue Ray,
taśmy,...).
Większość programów (przeglądarki WWW, kompilatory,
procesory tekstu, arkusze kalkulacyjne itd.) przechowuje się
na dysku, zanim nie nastąpi ich umieszczenie w pamięci
operacyjnej.
Wiele programów używa potem dysku zarówno jako źródła,
jak i miejsca przeznaczenia przetwarzanych przez siebie
informacji.
Dlatego też właściwe zarządzanie pamięcią dyskową na
zasadnicze znaczenie w systemie komputerowym.
Przetwarzane przez
procesor dane pochodzą z
pamięci operacyjnej
Pamięć operacyjna oraz rejestry wbudowane w procesor
są jedynymi rodzajami pamięci dostępnej dla jednostki
centralnej bezpośrednio.
Zauważmy, że istnieją rozkazy, których argumentami są
adresy pamięci operacyjnej, lecz nie ma rozkazów
posługujących się adresami dyskowymi.
Z tego powodu każdy wykonywany rozkaz i wszystkie
używane przez niego dane muszą znajdować się w
jednym
z
tych
urządzeń
pamięci
o
dostępie
bezpośrednim.
Jeżeli danych nie ma w pamięci operacyjnej, to należy je
do niej sprowadzić, zanim jednostka centralna zacznie je
przetwarzać.
Wejście-wyjście
odwzorowane w pamięci
W przypadku urządzeń wejścia-wyjścia każdy
sterownik
wejścia-wyjścia
zawiera,
jak
wspomnieliśmy
wcześniej,
rejestry
do
przechowywania rozkazów i przesyłanych danych.
Specjalne operacje wejścia-wyjścia umożliwiają
przesyłanie
danych
między
tymi
rejestrami
a pamięcią systemu. Aby ułatwić dostęp do
urządzeń wejścia-wyjścia, w wielu architekturach
komputerów
stosuje
się
wejście-wyjście
odwzorowywane w pamięci (ang. memory-
mapped I/O).
Praca z I/O
odwzorowanym w pamięci
W tym przypadku pewna część adresów pamięci
operacyjnej zostaje wydzielona i odwzorowana na
rejestry urządzeń.
Operacje czytania i zapisywania miejsc określonych
przez te adresy powodują przesyłanie danych z lub do
rejestrów urządzeń.
Metoda ta jest odpowiednia dla urządzeń o krótkich
czasach reakcji, takich jak sterowniki wideo (kart
graficznych). W komputerze IBM PC każde miejsce
ekranu jest odwzorowane w komórce pamięci.
Wyświetlanie tekstu na ekranie jest niemal tak samo
łatwe, jak jego wpisywanie do odpowiednich miejsc
odwzorowanych w pamięci.
Porty I/O
Odwzorowywanie w pamięci wejścia-wyjścia
jest także wygodne dla innych urządzeń,
takich jak porty szeregowe i równoległe,
stosowane do podłączania do komputerów
modemów, drukarek, itp.
Za pomocą tego rodzaju urządzeń jednostka
centralna przesyła dane, czytając i zapisując
niewielką liczbę rejestrów urządzeń zwanych
portami wejścia-wyjścia (ang. I/O ports).
I/O programowane i
sterowane przerwaniami
Aby wysłać długi ciąg bajtów przez odwzorowany w pamięci port
szeregowy, procesor wpisuje jeden bajt danych do rejestru danych, a
następnie ustawia bit w rejestrze kontrolnym na wartość
sygnalizującą, że bajt jest dostępny.
Urządzenie pobiera ten bajt danych i zeruje bit w rejestrze
kontrolnym, sygnalizując, że jest gotowe na przyjęcie kolejnego bajta.
Procesor może wówczas przesłać następny bajt. Jeżeli procesor
stosuje odpytywanie do obserwowania bitu kontrolnego, wciąż
wykonując pętlę sprawdzania, czy urządzenie jest gotowe, to taką
metodę działania nazywa się programowanym wejściem-
wyjściem (ang. programmed I/O - PIO).
Jeżeli procesor nie odpytuje portu kontrolnego, otrzymując w zamian
przerwanie, gdy urządzenie stanie się gotowe na przyjęcie
następnego bajta, to o takim przesyłaniu danych mówi się, że jest
sterowane przerwaniami (ang. interrupt driven).
Dostęp do pamięci
wymaga „dłuższego”
czasu
Rejestry wbudowane w jednostkę centralną są na ogół dostępne w
jednym cyklu jej zegara. Większość procesorów może dekodować
rozkazy i wykonywać proste działania na zawartości rejestrów z
szybkością jednej lub więcej operacji na jeden impuls zegara.
Nie można tego powiedzieć o pamięci operacyjnej, do której dostęp
odbywa się za pośrednictwem transakcji z szyną pamięci. Dostęp
do pamięci może zajmować wiele cykli, a wtedy procesor zazwyczaj
musi utykać (ang. stall), gdyż brakuje mu danych do zakończenia
rozkazu, który właśnie wykonuje. Jest to sytuacja nie do
przyjęcia, zważywszy na częstość kontaktów z pamięcią.
Ratunkiem jest wstawienie między jednostkę centralną a pamięć
operacyjną jakiejś szybkiej pamięci. Bufor pamięci stosowany do
niwelowania różnic w szybkości nazywa się pamięcią podręczną
(ang. cache) (o czym więcej w dalszej części wykładu).
Dyski magnetyczne
Dyski magnetyczne stanowią zdecydowaną większość pamięci
pomocniczych współczesnych systemów komputerowych.
Zasada działania dysków jest stosunkowo prosta:
Każda płyta (ang. platter) dysku ma kształt kolisty, jak płyta
kompaktowa. Średnice popularnych płyt wahają się w przedziale
od 1 do 5,25 cala.
Obie powierzchnie płyty są pokryte materiałem magnetycznym,
podobnym do stosowanego na taśmach magnetycznych.
Informacje przechowuje się przez odpowiednie namagnesowanie
warstwy magnetycznej.
Głowice odczytająco-zapisujące unoszą się tuż nad powierzchnią
każdej płyty. Są one przymocowane do ramienia dysku (ang.
disk arm), które przemieszcza je wszystkie jednocześnie.
Budowa i logiczny podział
dysku
Powierzchnia
płyty
jest
logicznie
podzielona
na
koliste ścieżki (ang. tracks),
które z kolei dzielą się na
sektory
(ang.
sectors).
Zbiór ścieżek przy danym
położeniu ramienia tworzy
cylinder (ang. cylinder).
Na dysku mogą być tysiące
koncentrycznych cylindrów,
a
każda
ścieżka
może
zawierać setki sektorów.
Pojemność
pamięci
popularnych
napędów
dysków
mierzy
się
w
gigabajtach.
Parametry dysków
Podczas pracy dysk wiruje z dużą prędkością, wprawiany w ruch
przez silnik jego napędu. Prędkość obrotowa większości napędów
wynosi od 60 do 250 obrotów na sekundę.
Szybkość dysku jest określana przez dwa czynniki. Tempo
przesyłania (ang. transfer rate) oznacza szybkość, z jaką dane
przepływają między napędem dysku a komputerem. Na czas
ustalania położenia głowicy (ang. positioning time), niekiedy
nazywany czasem losowego dostępu (ang. random access time)
składają się: czas przesuwania głowicy do odpowiedniego cylindra,
nazywany czasem wyszukiwania (ang. seek time), oraz czas, w
którym potrzebny sektor, obracając się, przejdzie pod głowicą. Czas
ten jest nazywany opóźnieniem obrotowym (ang. rotational
latency).
Typowe dyski mogą przesyłać kilka-kilkanaście megabajtów danych
na sekundę, a ich czasy wyszukiwania i opóźnienia obrotowe
wynoszą kilka milisekund.
Dyski elastyczne
Dyski elastyczne (ang. floppy disks) są niedrogimi
wymiennymi dyskami, mającymi miękką, plastikową
obudowę, zawierającą giętką płytę.
Głowica dysku elastycznego z reguły spoczywa na jego
powierzchni, dlatego jego napęd jest zaprojektowany
na wolniejsze obroty niż napęd dysku twardego, aby
zmniejszyć ścieranie powierzchni dyskowej.
Typowa pojemność pamięci dysku elastycznego wynosi
zaledwie ok. 1,5 MB. Są również w użyciu dyski
wymienne działające niczym zwykłe dyski twarde i
mające pojemności mierzone w gigabajtach.
Sterowniki
Napęd dysku jest podłączony do komputera za
pomocą wiązki przewodów nazywanych szyną
wejścia-wyjścia (ang. I/O bus).
Jest kilka rodzajów szyn, w tym EIDE, SATA i SCSI.
Przesyłanie danych szyną odbywa się pod nadzorem
specjalnych,
elektronicznych
procesorów,
nazywanych sterownikami (ang. controllers).
Sterownik macierzysty (ang. host controller) to
sterownik po stronie szyny przylegającej do
komputera. Sterownik dysku (ang. disk controller)
jest wbudowany w każdy napęd dyskowy.
Realizacja dyskowych
operacji I/O
Aby wykonać dyskową operację wejścia-wyjścia, komputer
umieszcza rozkaz w sterowniku macierzystym, na ogół za
pomocą portów wejścia-wyjścia odwzorowanych w pamięci.
Sterownik macierzysty wysyła następnie polecenie w formie
komunikatu do sterownika dysku, a ten uruchamia napęd
dysku w celu wykonania polecenia.
Sterowniki dysków zazwyczaj mają wbudowaną pamięć
podręczną.
Przesyłanie danych w sterowniku dysku odbywa się między
pamięcią podręczną a powierzchnią dyskową,
natomiast przesyłanie danych po stronie komputera przebiega
szybko, bo z szybkościami układów elektronicznych i zachodzi
między pamięcią podręczną a sterownikiem macierzystym.
Taśmy magnetyczne
(ang. magnetic tape)
Jako nośnik pamięci pomocniczej była używana od dawna. Choć
jest ona względnie trwała i można na niej przechowywać wielkie
ilości danych, ma długi czas dostępu w porównaniu z pamięcią
operacyjną.
Dostęp losowy do taśmy magnetycznej jest tysiące razy
wolniejszy niż dostęp losowy do dysku magnetycznego, toteż
taśmy nie są wygodne w roli pamięci pomocniczej.
Taśm używa się głównie do przechowywania informacji rzadko
używanych, sporządzania kopii zapasowych oraz jako środka do
transportu informacji z jednego systemu do drugiego.
Taśma znajduje się na szpuli i przewija się w jedną bądź w drugą
stronę pod głowicą odczytująco-zapisującą. Przesunięcie taśmy
do właściwego miejsca może zajmować minuty, lecz z chwilą jego
odnalezienia napędy taśmowe mogą zapisywać dane z
szybkościami porównywalnymi do szybkości napędów dysków.
Rejestry
Pamięć podręczna
Pamięć operacyjne
Dysk elektroniczny
Dysk magnetyczny
Dysk optyczny
Taśma magnetyczna
Hierarchia pamięci
Rozmaite rodzaje pamięci w
systemie
komputerowym
można
zorganizować
w
hierarchię (rys.) zależnie od
ich szybkości i kosztów.
Na najwyższych poziomach
pamięci są drogie, za to
szybkie.
W miarę
przemieszczania
się w dół hierarchii, ogólnie
biorąc maleje cena jednego
bitu, natomiast wydłuża się
czas dostępu.
Pamięci (nie)ulotne
Oprócz szybkości i kosztu różnych systemów pamięci
uwzględnia się także jej ulotność.
Pamięć ulotna traci zawartość po odłączeniu od niej
zasilania.
W razie braku drogich, rezerwowych źródeł zasilania
(baterii lub generatorów) w celu bezpiecznego
przechowywania
dane
należy
zapisywać
w
pamięciach nieulotnych.
W hierarchii pokazanej na rys. (poprzedni slajd)
systemy pamięci leżące powyżej różnych typów
dysków są ulotne, a te, które znajdują się poniżej
pamięci operacyjnej, są nieulotne.
Niwelowanie różnic w
prędkości
Projektując pełny system pamięci, należy
równoważyć wszystkie te czynniki.
Drogiej pamięci używa się tylko w niezbędnych
ilościach, natomiast pamięci taniej i nieulotnej
dostarcza się w ilościach możliwie dużych.
W celu niwelowania różnic w wydajności, tam,
gdzie występują długie czasy dostępu lub
dysproporcje w szybkości przesyłania między
dwoma składowymi, można instalować pamięci
podręczne.
Jak system wykorzystuje
pamięć podręczną?
Stosowanie pamięci podręcznej (ang. caching) jest ważną
zasadą przy projektowaniu systemów komputerowych.
W normalnych warunkach informacje są przechowywane
w jakimś systemie pamięci (np. w pamięci operacyjnej).
Przed ich użyciem są kopiowane do szybszego systemu
pamięci - tj. do pamięci podręcznej - na okres przejściowy.
Gdy jest potrzebny jakiś fragment informacji, wtedy
sprawdza się najpierw, czy nie ma go w pamięci podręcznej.
Jeśli jest, informacje pobiera się wprost z pamięci
podręcznej; jeśli zaś nie, to korzysta się z informacji w
głównym systemie pamięci, umieszczając ich kopię w
pamięci podręcznej przy założeniu, że istnieje duże
prawdopodobieństwo, że będą one znów potrzebne.
Zarządzanie pamięcią
podręczną (ang. cache
management)
Jest ważnym zagadnieniem projektowym ze względu na
ograniczone rozmiary tych pamięci.
Staranny dobór wielkości pamięci podręcznej i polityki
zastępowania w niej informacji może spowodować, że 80 do
99% wszystkich dostępów będzie się odnosić do pamięci
podręcznej, co w dużym stopniu usprawni działanie systemu.
Pamięć operacyjną (główną) można uważać za szybką
pamięć podręczną dla pamięci pomocniczej, gdyż dane z
pamięci pomocniczej muszą być przed użyciem kopiowane
do pamięci operacyjnej, a dane przeznaczone do
przemieszczenia
do
pamięci
pomocniczej
w
celu
bezpiecznego przechowywania muszą wpierw znajdować się
w pamięci operacyjnej.
Gdzie przechowywane są
dane systemu plików w
trakcie pracy systemu ?
Dane systemu plików mogą występować na kilku
poziomach w hierarchii pamięci.
Na najwyższym poziomie system operacyjny może
utrzymywać pamięć podręczną danych systemu plików
w pamięci operacyjnej. Do bardzo szybkiego, ulotnego
pamiętania można również stosować elektroniczne RAM-
dyski, udostępniane za pomocą interfejsu systemu
plików. Duża ilość pamięci pomocniczej znajduje się na
dyskach magnetycznych.
Pamięć dysków magnetycznych jest z kolei często
składowana na taśmach lub dyskach wymiennych w celu
ochrony przed utratą danych w przypadku awarii dysku
twardego.
Jawne i niejawne
przemieszczanie
informacji w hierarchii
pamięci
Przemieszczanie informacji między poziomami
hierarchii pamięci może być jawne lub niejawne -
zależnie od konstrukcji sprzętu i nadzoru ze strony
oprogramowania systemu operacyjnego.
Na przykład przesyłanie danych z pamięci
podręcznej do jednostki centralnej i rejestrów jest
zwykle funkcją sprzętową, nie wymagającą żadnej
interwencji ze strony systemu operacyjnego.
Z kolei przesyłanie danych z dysku do pamięci
operacyjnej jest zazwyczaj nadzorowane przez
system operacyjny.
Problemy związane z
hierarchiczną strukturą
pamięci
W hierarchicznej strukturze pamięci te same dane mogą
występować na różnych jej poziomach.
Rozważmy na przykład liczbę całkowitą A umieszczoną w pliku B,
która ma być zwiększona o 1. Załóżmy, że plik B rezyduje na
dysku magnetycznym.
Operację zwiększania poprzedza wykonanie operacji wejścia-
wyjścia mającej na celu skopiowanie bloku dyskowego z liczbą A
do pamięci operacyjnej. Po tej z kolei operacji może nastąpić
przekopiowanie A do pamięci podręcznej, a stamtąd - do
wewnętrznego rejestru.
Tak więc kopia liczby A pojawia się w kilku miejscach. Z chwilą
wykonania operacji zwiększania w rejestrze wewnętrznym
wartość A będzie różna w różnych systemach pamięci. Stanie się
ona taka sama dopiero po przekopiowaniu jej z powrotem na dysk
magnetyczny.
Problemy związane z
hierarchiczną strukturą
pamięci
cd.
W środowisku, w którym w danym czasie jest
wykonywany tylko jeden proces, sytuacja taka nie
powoduje żadnych trudności, ponieważ dostęp do
liczby całkowitej A będzie dotyczyć zawsze jej kopii
na najwyższym poziomie hierarchii.
Jednak w środowisku wielozadaniowym, w którym
procesor jest przełączany tam i z powrotem między
różnymi procesami, należy przedsięwziąć skrajne
środki ostrożności, aby zapewnić, że w przypadku
gdy kilka procesów będzie chciało sięgnąć po A,
wówczas każdy z nich otrzyma jej najnowszą
wartość.
Zgodność i spójność
Sytuacja staje się bardziej skomplikowana w środowisku
wieloprocesorowym,
gdzie
-
oprócz
utrzymywania
wewnętrznych rejestrów - jednostka centralna zawiera również
lokalną pamięć podręczną. W takim środowisku kopia zmiennej
A może istnieć jednocześnie w wielu pamięciach podręcznych.
Ponieważ różne jednostki centralne mogą działać jednocześnie,
musimy więc zapewnić, że uaktualnienie wartości A w jednej z
pamięci podręcznych znajdzie natychmiast odbicie we
wszystkich innych pamięciach podręcznych, które również
przechowują zmienną A. Problem ten zwie się problemem
zgodności pamięci podręcznej (ang. cache coherency) i
zazwyczaj jest rozwiązywany sprzętowo (jego obsługa odbywa
się poniżej poziomu systemu operacyjnego).
Ochrona sprzętowa -
wprowadzenie
Wczesne
systemy
komputerowe
były
systemami
jednostanowiskowymi,
w
których
programista
był
zarazem
operatorem. Programiści obsługujący komputer za pomocą konsoli
sprawowali nad nim pełny nadzór.
Z chwilą powstania systemów operacyjnych nadzór przekazano
systemowi operacyjnemu, który zaczął wykonywać wiele funkcji,
zwłaszcza dotyczących wejścia-wyjścia, za które uprzednio był
odpowiedzialny programista.
Ponadto, aby polepszyć wykorzystanie systemu, system operacyjny
począł dzielić (ang. share) zasoby systemowe między pewną liczbę
programów jednocześnie. Przy użyciu spoolingu można było
wykonywać jeden program, a jednocześnie radzić sobie z
przesyłaniem danych do innych procesów; dysk przechowywał
jednocześnie dane dla wielu procesów. Wieloprogramowość
spowodowała konieczność koegzystencji wielu programów w pamięci
w tym samym czasie.
„Rozbrykane” programy
Ów podział spowodował zarówno poprawę użytkowania, jak i
zwiększenie liczby problemów.
Gdy system działał bez podziału, wówczas błąd w programie mógł
powodować trudności tylko w jednym programie, który właśnie był
wykonywany.
W sytuacji podziału zasobów komputera na szkodliwe skutki błędu
w jednym programie mogło być narażonych wiele procesów.
W systemach wieloprogramowych mogłyby się zdarzać znacznie
trudniejsze do wykrycia błędy, gdyby jakiś „rozbrykany" program
pozmieniał dane innego programu lub nawet program samego
monitora rezydentnego (systemu operacujnego).
Zarówno system MS-DOS (i 16-bitowe Windows), jak i Macintosh
OS (wczesne wersje) dopuszczały występowanie błędów tego
rodzaju.
Potrzebna jest ochrona
Bez ochrony przed tego rodzaju błędami komputer musi
wykonywać w danej chwili tylko jeden proces albo wszystkie
wyniki należy uznać za podejrzane.
Dobrze
zaprojektowany
system
operacyjny
musi
gwarantować, że niepoprawny (lub „złośliwy”) program nie
będzie mógł zakłócić działania innych programów.
Wiele błędów programowania jest wykrywanych przez
sprzęt. Tymi błędami zajmuje się na ogół system operacyjny.
Gdy program użytkownika dopuści się jakiegoś uchybienia,
na przykład próbuje wykonać niedozwolony rozkaz lub
sięgnąć po komórkę pamięci nie należącą do jego
przestrzeni adresowej, wpadnie wówczas w pułapkę
zastawioną przez sprzęt, co oznacza przejście do systemu
operacyjnego.
Pułapki
Tak jak przerwanie, pułapka powoduje przejście do systemu
operacyjnego za pomocą wektora przerwań.
Za każdym razem, gdy wystąpi błąd w programie, system
operacyjny wymusza nienormalne zakończenie programu.
Zdarzenie takie jest obsługiwane za pomocą tego samego
kodu co żądanie nienormalnego zakończenia programu
pochodzące od użytkownika.
Pojawia się odpowiedni komunikat o błędzie, po czym
następuje składowanie pamięci programu. Obraz pamięci
programu jest zazwyczaj zapisywany w pliku, użytkownik
może go więc przeanalizować i, po ewentualnej poprawce
(bądź bez niej), spróbować uruchomić program od nowa.
Dualny tryb wykonywania
operacji
Aby zapewnić poprawną pracę, musimy chronić system
operacyjny i wszystkie inne programy oraz ich dane przed
każdym niewłaściwie działającym programem. Ochroną
muszą być objęte wszystkie wspólnie wykorzystywane
zasoby.
Ta metoda postępowania polega na zaopatrzeniu sprzętu w
środki pozwalające na rozróżnianie rozmaitych trybów jego
pracy.
Potrzebujemy rozróżniania co najmniej dwu oddzielnych
trybów pracy: trybu użytkownika (ang. user mode) i trybu
monitora (ang. monitor mode), nazywanego także trybem
nadzorcy (ang. supervisor mode), trybem systemu (ang.
system mode) lub trybem uprzywilejowanym (ang.
privileged mode).
Działanie w dualnym
trybie wykonywania
operacji
W sprzęcie komputerowym istnieje bit, zwany bitem
trybu (ang. mode bit), którego stan wskazuje bieżący
tryb pracy: monitor (0) albo użytkownik (1).
Za pomocą bitu trybu można odróżnić działania
wykonywane na zamówienie systemu operacyjnego od
działań wykonywanych na zamówienie użytkownika.
W czasie rozruchu systemu sprzęt rozpoczyna działanie
w trybie monitora. Następuje załadowanie systemu
operacyjnego, który uruchamia procesy użytkowe w
trybie użytkownika. Za każdym razem po wystąpieniu
pułapki lub przerwania sprzęt zmienia tryb pracy z trybu
użytkownika na tryb monitora (tzn. zmienia wartość bitu
trybu na 0).
Rozkazy uprzywilejowane
Dualny tryb działania komputera dostarcza środków do
ochrony systemu operacyjnego przed nieodpowiedzialnymi
użytkownikami, a także do chronienia nieodpowiedzialnych
użytkowników wzajemnie przed sobą.
Ochrona ta jest uzupełniana za pomocą oznaczenia
potencjalnie niebezpiecznych rozkazów kodu maszynowego
jako rozkazów uprzywilejowanych (ang. privileged
instructions).
Sprzęt pozwala wykonywać rozkazy uprzywilejowane tylko w
trybie monitora. Próba wykonania rozkazu uprzywilejowanego
w trybie użytkownika nie zakończy się wykonaniem go przez
sprzęt. Przeciwnie - rozkaz zostanie przez sprzęt
potraktowany jako niedopuszczalny i spowoduje awaryjne
przejście do systemu operacyjnego.
Brak sprzętowych środków do
organizacji dualnego trybu pracy
może powodować poważne
następstwa
System operacyjny MS-DOS napisano dla procesora Intel 8088,
który nie ma bitu trybu, a więc i dwu trybów pracy. Niepoprawny
przebieg wykonania programu użytkownika może spowodować
zniszczenie systemu operacyjnego przez zapisanie jego kodu
danymi.
Jeśli zaś wiele programów pisałoby równocześnie na jednym
urządzeniu wyjściowym, to mogłoby powstać bezsensowne
wyniki.
W późniejszym czasie ulepszone wersje jednostek centralnych
Intela, takie jak 80486, zostały wyposażone w dualny tryb
operacji. W rezultacie w nowszych systemach operacyjnych,
takich jak Microsoft Windows NT/2000/XP, Linux, Unix, MacOS i
IBM OS/2, skorzystano z tej właściwości, dzięki czemu są one
objęte lepszą ochroną.
Ochrona wejścia-wyjścia
Program użytkownika może zakłócić normalne działanie systemu,
wydając niedozwolony rozkaz wejścia-wyjścia, docierając do komórek
pamięci w obrębie samego systemu operacyjnego lub nie zwalniając
procesora.
Możemy zastosować różne mechanizmy nie dopuszczające do
powstawania tego rodzaju zakłóceń w systemie.
Aby ustrzec użytkownika przed wykonywaniem niedozwolonych
operacji wejścia-wyjścia, przyjęto, że wszystkie rozkazy wejścia-wyjścia
są uprzywilejowane.
Użytkownicy nie mogą wobec tego używać bezpośrednio tych
rozkazów, lecz muszą to robić za pośrednictwem systemu
operacyjnego.
Aby uzyskać pełną ochronę wejścia-wyjścia, należy mieć pewność, że
program użytkownika nigdy nie przejmie kontroli nad komputerem
w trybie pracy monitora. Gdyby mu się to udało, ochrona zostałaby
naruszona.
Przykład
Rozważmy komputer, który pracuje w trybie użytkownika.
Będzie on przechodzić w tryb monitora przy każdym
wystąpieniu przerwania lub pułapki, wykonując skok pod
adres określony w wektorze przerwań.
Załóżmy, że program użytkownika umieściłby nowy adres
w wektorze przerwań. Ten nowy adres mógłby zastąpić
poprzedni adres i wskazać miejsce w programie użytkownika.
Wówczas po wystąpieniu odpowiedniego przerwania sprzęt
przełączyłby komputer w tryb monitora i przekazał
sterowanie według (zmienionego) wektora przerwań
do programu użytkownika!
Program użytkownika przejąłby kontrolę nad komputerem w
trybie monitora.
Wnioski z przykładu
Aby zapewnić poprawne działanie, musimy chronić wektor
przerwań przed zmianami, które mógłby wprowadzić program
użytkownika.
Ponadto przed modyfikacjami należy również chronić systemowe
procedury obsługi przerwań. W przeciwnym razie program
użytkownika mógłby rozkazy w procedurze obsługi przerwania
zastąpić skokami do własnego obszaru, przechwytując sterowanie
od procedury obsługi przerwania, pracującej w trybie monitora.
Jeśli nawet użytkownik nie uzyskałby bezprawnej możliwości
sterowania pracą komputera, to zmiany w procedurach obsługi
przerwań zakłóciłyby prawdopodobnie właściwe działanie
systemu komputerowego, przebieg spoolingu i buforowania.
Widzimy, że należy zapewnić ochronę pamięci przynajmniej w
odniesieniu do wektora przerwań i systemowych procedur obsługi
przerwań.
Jak uzyskać ochronę
pamięci ?
Na ogół jednak zależy nam na ochronie całego systemu
operacyjnego przed wpływami programów użytkowników,
a ponadto
-
na
wzajemnej
ochronie
programów
użytkowników. Tę ochronę musi zapewniać sprzęt. Aby
oddzielić od siebie obszary pamięci każdego programu,
musimy
mieć
możność
rozstrzygania
o
zakresie
dopuszczalnych adresów programu i chronienia pamięci poza
tymi adresami.
Tego rodzaju ochronę można uzyskać za pomocą dwu
rejestrów, zwanych bazowym i granicznym (ang. base,
limit), (rys. na następnym slajdzie)
Rejestr bazowy przechowuje najmniejszy dopuszczalny adres
fizyczny pamięci, a rejestr graniczny zawiera rozmiar
obszaru pamięci.
Rejestr bazowy i rejestr
graniczny definiują logiczną
przestrzeń adresową
Jeśli
na
przykład
zawartość
rejestru
bazowego
wynosi
300040, a rejestru
granicznego - 120900,
to jako poprawne w
programie
mogą
wystąpić odniesienia
do
wszystkich
adresów od 300040
do 420940 włącznie.
Sprzętowa ochrona
adresów z rejestrami -
bazowym i granicznym
Ochronę
taką
sprawuje sprzęt
jednostki
centralnej
przez,
porównywanie
każdego adresu
wygenerowane
go
w
trybie
pracy
użytkownika z
zawartością
opisanych
rejestrów.
Jakiekolwiek
usiłowanie
programu
pracującego w trybie użytkownika uzyskania
dostępu do pamięci monitora lub programu
innego użytkownika kończy się przejściem
do monitora, który traktuje taki zamiar jako
poważny błąd.
Zmian obu rejestrów
może dokonać jedynie OS
W takim schemacie program użytkownika jest chroniony
przed (przypadkowym lub zamierzonym) zmodyfikowaniem
kodu lub struktur danych systemu operacyjnego lub innych
użytkowników.
Zawartości rejestrów - bazowego i granicznego - mogą być
określone przez system operacyjny przy użyciu specjalnych,
uprzywilejowanych rozkazów.
Ponieważ rozkazy uprzywilejowane można wykonać tylko w
trybie monitora, a jednocześnie tylko system operacyjny
może pracować w tym trybie, więc jedynie system operacyjny
może załadować rejestr bazowy i graniczny.
Schemat taki umożliwia monitorowi zmienianie wartości tych
rejestrów i nie pozwala zmieniać ich stanu przez programy
użytkownika.
OS duże możliwości, ale
może stracić sterowanie
System operacyjny, działając w trybie monitora, ma
nieograniczony dostęp zarówno do swojej pamięci, jak i do
pamięci użytkowników.
Dzięki temu system operacyjny może ładować programy
użytkowników do przeznaczonych dla nich obszarów
pamięci, w razie wystąpienia błędów może dokonywać
składowań tych obszarów, ma dostęp do parametrów funkcji
systemowych, które może modyfikować itd.
Ważnym elementem ochrony systemu przed zakłóceniami
jest zapewnienie, że system operacyjny utrzymuje stałą
kontrolę. Musimy zapobiec temu, żeby program użytkownika
nie wpadł w nieskończoną pętlę, gdyż grozi to odebraniem
sterowania systemowi operacyjnemu na zawsze.
Na wszelki wypadek OS
stosuje czasomierze
Zabezpieczenie osiąga się poprzez zastosowanie
czasomierza.
Czasomierz (ang. timer) można ustawić tak, aby
generował
w
komputerze
przerwanie
po
wyznaczonym okresie.
Okres ten może być stały (np. 1/60 s) lub zmienny
(np. od 1ms do 1s, z przyrostami co 1ms).
Odmierzanie zmiennych okresów implementuje się
za pomocą zegara stałookresowego i licznika.
System operacyjny ustawia licznik. Przy każdym
tyknięciu zegara następuje zmniejszenie licznika.
Z chwilą wyzerowania licznika powstaje przerwanie.
OS dzięki czasomierzowi
odzyskuje kontrolę
Przed oddaniem sterowania do programu użytkownika
system operacyjny dopilnowuje ustawienia czasomierza na
przerwanie.
Kiedy czasomierz powoduje przerwanie, wtedy sterowanie
wraca automatycznie do systemu operacyjnego, który może
uznać to przerwanie za poważny błąd lub zdecydować o
przyznaniu programowi większej ilości czasu.
Rozkazy modyfikujące działanie czasomierza są oczywiście
zastrzeżone na użytek monitora.
W ten sposób czasomierz może być użyty do zapobiegania
zbyt długiemu działaniu programu użytkownika. Proste
postępowanie polega na zapamiętaniu w liczniku, ile czasu
przydziela się programowi na wykonanie.
Przełączanie kontekstu w
systemach z podziałem
czasu
Powszechniejsze zastosowanie czasomierza występuje w realizacji
podziału czasu.
W najprostszym przypadku czasomierz może być nastawiony na
przerywanie co każde N ms, gdzie N jest kwantem czasu (ang. time
slice) przydzielanym każdemu użytkownikowi na działanie, zanim
następny użytkownik nie przejmie nadzoru nad procesorem.
System operacyjny jest wywoływany po upływie każdego kwantu
czasu w celu wykonania rozmaitych prac administracyjnych, jak
dodanie
wartości
N
do
rekordu
określającego
(w celach
rozliczeniowych) ilość czasu, którą program użytkownika zużył do tej
pory.
System operacyjny odświeża również stany rejestrów, zmiennych
wewnętrznych i buforów oraz zmienia kilka innych parametrów,
przygotowując następnemu programowi pole do działania. Procedura
ta nosi nazwę przełączania kontekstu (ang. context switch).
Wyznaczanie bieżącego
czasu
Innym zastosowaniem czasomierza jest obliczanie bieżącego
czasu. Przerwania czasomierza sygnalizują upłynięcie pewnej
jednostki czasu, co pozwala systemowi operacyjnemu na
obliczanie bieżącego czasu w odniesieniu do pewnej wartości
początkowej.
Jeśli przerwania następują co 1 s i zdarzyło się ich 1427, odkąd
powiedzieliśmy, że jest pierwsza po południu, to można obliczyć,
że obecnie jest godzina 13:23:47. Niektóre komputery
wyznaczają bieżący czas w opisany sposób.
Wskazywanie dokładnego czasu wymaga jednak starannych
obliczeń, ponieważ czas przetwarzania przerwań (i czas
wyłączonych
przerwań)
powoduje
opóźnianie
takiego
programowego zegara. Większość komputerów ma oddzielny,
sprzętowy zegar czasu rzeczywistego, na który system
operacyjny nie ma wpływu.
Ochrona systemu -
podsumowanie
Zapotrzebowanie
na
polepszanie
wykorzystania
systemu
komputerowego doprowadziło do rozwoju wieloprogramowości i
podziału czasu, w których to warunkach zasoby systemu
komputerowego są dzielone między wiele różnych programów i
procesów.
Wspólne użytkowanie zasobów wpłynęło bezpośrednio na zmiany
podstawowej architektury komputera, umożliwiające systemowi
operacyjnemu nadzorowanie pracy systemu komputerowego, a
zwłaszcza
urządzeń
wejścia-wyjścia.
Nadzorowanie
jest
nieodzowne do tego, aby działanie komputera było ciągłe, spójne
i poprawne.
Do sprawowania nadzoru konstruktorzy zastosowali dualny tryb
pracy komputera (tryb użytkownika i tryb monitora). Schemat ten
opiera się na koncepcji rozkazów uprzywilejowanych, których
wykonywanie jest możliwe tylko w trybie monitora.
Wykonywanie dozwolonych
operacje WE/WY przez
programy użytkowników
Rozkazy wejścia-wyjścia - jako uprzywilejowane - mogą być
wykonywane tylko przez system operacyjny. Jak zatem program
użytkownika może wykonać operację wejścia-wyjścia?
Czyniąc te rozkazy uprzywilejowanymi, odgradzamy programy
użytkownika od wykonywania jakichkolwiek operacji wejścia-
wyjścia - zarówno niedozwolonych, jak i dozwolonych.
Problem ten rozwiązuje się w ten sposób, że skoro tylko monitor
może wykonywać operacje wejścia-wyjścia, to użytkownik musi
poprosić monitor, aby wykonał on taką operację w jego
imieniu.
Prośba taka nosi nazwę wywołania systemowego (ang.
system call), a bywa też nazywana wywołaniem monitora lub
wywołaniem funkcji systemu operacyjnego.
Wywołanie systemowe
Wywołanie systemowe jest rozpoczynane na wiele
sposobów, w zależności od właściwości danego
procesora. We wszystkich odmianach jest to
metoda, za pomocą której proces zamawia
działanie systemu operacyjnego.
Wywołanie systemowe zwykle przyjmuje postać
przejścia do określonej komórki w wektorze
przerwań. Przejście to może być wykonywane za
pomocą ogólnego rozkazu trap, choć w niektórych
systemach) występuje specjalny rozkaz syscall.
Co robi wywołanie
systemowe ?
Wywołanie systemowe jest traktowane przez sprzęt tak jak
przerwanie programowe. Za pośrednictwem wektora przerwań
sterowanie jest przekazywane do odpowiedniej procedury obsługi
w systemie operacyjnym, a bit trybu zostaje przełączony w tryb
monitora. Procedura obsługi wywołania systemowego jest częścią
systemu operacyjnego.
Monitor sprawdza rozkaz przerywający, aby określić, które
wywołanie systemu miało miejsce.
Rodzaj usługi, na którą użytkownik zgłasza zapotrzebowanie, jest
określony przez parametr wywołania systemowego. Dodatkowe
informacje potrzebne w związku z zamówieniem na obsługę mogą
być przekazane za pomocą rejestrów lub pamięci (za pomocą
umieszczonych w rejestrach wskaźników do komórek pamięci).
Monitor wykonuje zamówienie i przekazuje sterowanie do rozkazu,
który następuje po wywołaniu systemowym.
Użycie odwołania do
systemu w celu wykonania
operacji wejścia-wyjścia
Tak więc, aby wykonać operację
wejścia-wyjścia,
program
użytkownika odwołuje się do
systemu, powodując że system
operacyjny wykona operację
wejścia-wyjścia
na
jego
życzenie.
System operacyjny, pracujący w
trybie
monitora,
sprawdza
poprawność zamówienia i - jeśli
jest
ono
dopuszczalne
-
wykonuje odpowiednią operację
wejścia-wyjścia.
Następnie
system operacyjny przekazuje
sterowanie
do
programu
użytkownika.