% Impala Operating System
%
% Copyright (C) 2009 University of Wroclaw. Department of Computer Science
%    http://www.ii.uni.wroc.pl/
% Copyright (C) 2009 Mateusz Kocielski, Artur Koninski, Pawel Wieczorek
%    http://bitbucket.org/wieczyk/impala/
% All rights reserved.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions
% are met:
% 1. Redistributions of source code must retain the above copyright
%  notice, this list of conditions and the following disclaimer.
% 2. Redistributions in binary form must reproduce the above copyright
%  notice, this list of conditions and the following disclaimer in the
%  documentation and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
% ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
% FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
% DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
% OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
% HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
% LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
% SUCH DAMAGE.
%
% $Id: vfs.tex 486 2009-06-25 07:51:47Z wieczyk $

\section{Interfejs terminali.}
\label{TTY}
Programy użytkownika wymagają od systemu ujednoliconego dostępu do urządzeń
umożliwiających im komunikację z użytkownikiem. Urządzenia służące do takiej
komunikacji nazywamy terminalami. Terminale można podzielić na następujące grupy:
\begin{enumerate}
\item Terminal zewnętrzny, komunikujący się z komputerem poprzez port szeregowy
bądź modem
\item Terminal zintegrowany z komputerem, komunikacja następuje np. poprzez
dzieloną pamięć. (Klawiatura, monitor)
\item Terminal sieciowy - komunikacja np. poprzez Ethernet
\end{enumerate}
Wszystkie te urządzenia widoczne są dla użytkownika w ujednoliconej formie - jako
urządzenia terminalowe. W systemie Impala z terminalami związana jest struktura
\texttt{tty\_t}. Rejestrowanie nowego urządzenia terminalowego w systemie
następuje poprzez funkcję \texttt{tty\_create}. Jako argumenty przyjmuje ona
nazwę nowego urządzenia, dowolną strukturę z prywatnymi danymi urządzenia, oraz
wskaźnik do funkcji obsługującej zapis na tym urządzeniu. W ten sposób, system
terminali stanowi nakładkę na inne urządzenia, implementującą ich typowe
funkcjonalności w zunifikowany sposób.
\subsection{Reżim linii.}
Aby zapewnić zgodność programów Unixowych z oferowanym przez nas interfejsem
terminali, został on zaprojektowany zgodnie ze standardem POSIX dotyczącym tej
kwestii. Standard reguluje jak ma przebiegać wejście, wyjście oraz zmiana
ustawień terminala.
\subsubsection{Zmiana ustawień.}
Najważniejsze ustawienia terminala przechowywane są w strukturze \texttt{termios}.
Zawiera ona następujące pola:

\begin{center}
\begin{tabular}{|l|l|}
\hline
tcflag\_t c\_iflag & Flagi konfigurujące zachowanie wejścia\\
tcflag\_t c\_oflag & Flagi konfigurujące zachowanie wyjścia\\
tcflag\_t c\_lflag & Ogólne flagi ustawiające tryb pracy terminala\\
tcflag\_t c\_cflag & Flagi związane z obsługą połączenia\\
cc\_t c\_cc[NCCS] & Znaki specjalne \\
\hline
\end{tabular}
\end{center}

Przeznaczenie poszczególnych pól zostanie przybliżone w kolejnych podrozdziałach.
Biblioteka C udostępnia funkcje do zapisu i odczytu aktualnych ustawień terminala
- są to odpowiednio \texttt{tcsetattr} i \texttt{tcgetattr}. Funkcje to zostały
zaimplementowane w oparciu o wywołanie systemowe \texttt{ioctl}.
\subsubsection{Otwieranie terminala, uprawnienia procesów.}
Terminal otwierany jest jak zwykły plik, przy pomocy wywołania systemowego
\texttt{open}. Aby umożliwić wielu programom jednoczesne korzystanie z jednego
terminala, oraz umożliwić kontrolę zadań w powłokach takich jak \texttt{ash},
wprowadzona została dodatkowa organizacja procesów.

Każdy proces może posiadać swój powiązany terminal kontrolujący. Ogólnie rzecz
biorąc, może on korzystać tylko z tego terminala.
Procesy zostały podzielone na sesje, oraz w ramach sesji na grupy.
Wszystkie procesy w ramach sesji, które mają ustawiony terminal kontrolujący,
mają ustawiony ten sam terminal. Tak więc terminal jest powiązany z sesją.
Terminal może być związany z tylko jedną sesją i vice versa.

W ramach sesji procesy tworzą rozłączne grupy, z których jedna może być
wyszczególniona jako grupa procesów pierwszoplanowych terminala. Procesy z tej
grupy jako jedyne mają dostęp do wejścia z terminala. Co do zapisu na terminal,
możliwy jest on także spoza grupy procesów pierwszoplanowych, jednak to wymaga
dodatkowych środków (w postaci blokowania lub ignorowania sygnału \texttt{SIGTTOU}).

Sesja oraz grupa procesów posiadają swój identyfikator, równy identyfikatorowi
procesu, który jako pierwszy do danego bytu należał.
Proces taki zwany jest odpowiednio liderem sesji i liderem grupy.
Do tworzenia nowej sesji wykorzystuje się funkcję \texttt{setsid}.
Terminal kontrolujący procesu ustawiany jest automatycznie, w momencie
otwierania go, o ile proces otwierający nie posiada już terminala kontrolującego,
jest liderem sesji, oraz terminal ten nie jest jeszcze związany z żadną sesją.
Terminal kontrolujący, sesję, oraz grupę proces dziedziczy po ojcu w wywołaniu
\texttt{fork}.

Pobieranie i modyfikacja grupy procesu realizowane są poprzez \texttt{getpgid}
i \texttt{setpgid}. Wybór grupy procesów pierwszoplanowych terminalu następuje
poprzez wywołanie \texttt{ioctl} na deskryptorze pliku terminala, z poleceniem
\texttt{TIOCSPGRP} (zobacz także \texttt{tcsetpgrp} i \texttt{tcgetpgrp}).
\subsubsection{Zapisywanie do terminala.}
% Można wywalić / skrócić, w związku z powielaniem treści już opisanych
Programy przekazują dane na wyjście terminala za pomocą jednej z funkcji biblioteki C,
zazwyczaj z rodziny \texttt{printf}.
Funkcja \texttt{printf} wywołuje poprzez przerwanie systemową funkcję \texttt{sc\_write}.
Ta z koleji, poprzez vnode związany z deskryptorem pliku przekazuje bufor z danymi
użytkownika do funkcji obsługi \texttt{tty\_write} urządzenia znakowego związanego z terminalem.

Zanim będzie mógł nastąpić faktyczny zapis danych przy pomocy funkcji zarejestrowanej
w procedurze \texttt{tty\_create}, funkcja \texttt{tty\_write} weryfikuje, czy
piszący proces ma do tego prawo, oraz w zależności od ustawień wykonuje końcowe
przekształcenia na danych użytkownika. Wykonywane przekształcenia uzależnione są
od wartości \texttt{c\_oflag}. Możliwe operacje to miedzy innymi zamiana znaków
\texttt{CR} (powrót karetki) na znaki \texttt{NL} (nowej linii) i zamiana znaków
\texttt{NL} na parę \texttt{CR-NL}.

\subsubsection{Odczyt z terminala.}
Urządzenie wejściowe otrzymawszy dane, przekazuje je do bufora powiązanego terminala
poprzez funkcję \texttt{tty\_input}. Użytkownik uzyskuje dostęp do tych danych
przy pomocy funkcji bibliotecznych takich jak \texttt{scanf}, korzystających z wywołania
systemowego \texttt{read}. Dane uzyskane w ten sposób to ciąg znaków ASCII.

Wyobraźmy sobie następującą sytuację: program pyta użytkownika, o podanie imienia,
ten jednak, w połowie wpisywanego tekstu popełnił błąd i skorygował go przy użyciu
klawisza backspace. Program jest zainteresowany jedynie poprawionym wpisem, a nie
ciągiem znaków zawierających błędne dane oraz kod ASCII klawisza backspace.
Jest to na tyle częsta sytuacja, że schemat obsługi wejścia, w którym sterownik
dba o obsługę zmian w ramach jednej lini wejścia został uwzględniony w standardzie
POSIX jako element interfejsu terminali. Oczywiście niektóre programy chcą
znać kody wszystkich naciskanych klawiszy, bez konieczności czekania na znak
nowej lini, tak więc i ta sytuacja musi być obsługiwana. Pierwszy tryb według
POSIX zwiemy trybem kanoniczym, drugi surowym. Tryb pracy terminala uzależniony jest od
obecności flagi \texttt{ICANON} w polu \texttt{c\_lflag} struktury opisującej
konfigurację terminala.
\subsubsection{Tryb kanoniczny.}
Domyślnie terminal znajduje się w trybie kanonicznym.
W trybie tym rozpoznawane są znaki specjalne, ustalone w polach tabeli
\texttt{c\_cc}. Należą do nich EOF, EOL, ERASE, INTR, KILL, QUIT, START, STOP,
SUSP i TIME. Sterownik dokonuje edycji linii w przypadku rozpoznania znaku ERASE
(usunięcie ostatniego znaku) bądź KILL (usunięcie całej lini). Jeżeli pole
\texttt{c\_lflag} zawiera flagę \texttt{ISIG}, wystąpienie znaków INTR, QUIT
oraz SUSP powoduje wysłanie do grupy procesów pierwszoplanowych odpowiednio
sygnału \texttt{SIGINT}, \texttt{SIGQUIT}, \texttt{SIGTSTP}.

Procedura \texttt{read} zwraca wynik, tylko w przypadku gdy
w buforze wejściowym terminala istnieje linia zakończona znakiem NL, EOF bądź EOL.
Jeżeli linia nie jest jeszcze gotowa, proces zasypia w oczekiwaniu na nią.
Zwrócony bufor zawiera co najwyżej jedną linię z wejścia.

W trybie kanonicznym na wejściu wykonywane jest wstępne przetwarzanie,
według wartości \texttt{c\_iflag}. Możliwe operacje to m.in. ignorowanie znaków
\texttt{CR}, zamiana znaku \texttt{CR} na znak \texttt{NL} i na odwrót.
\subsubsection{Tryb surowy.}
W trybie surowym znaki nie są dodatkowo przetwarzane. Poprzez ustawienie pól
\texttt{c\_cc[VMIN]} i \texttt{c\_cc[VTIME]} użytkownik może kontrolować
minimalną ilość znaków, jaka zostanie zwrócona przez \texttt{read}, oraz czas,
jaki procedura ma czekać na kolejny znak (bądź całość wejścia - przy \texttt{MIN}$=0$).
\subsection{Konsola.}
Jedynym w tej chwili zaimplementowanym w Impali terminalem jest konsola - zestaw
złożony z klawiatury i wyświetlacza podłączonego do karty graficznej.
Urządzenia te są widoczne w systemie jako kilka osobnych wirtualnych konsoli,
o plikach \texttt{/dev/ttyvX}, gdzie \texttt{X} jest numerem urządzenia.
Przełączanie pomiędzy tymi konsolami następuje po naciśnięciu odpowiedniego
klawisza funkcyjnego \texttt{Fx}.
\subsubsection{Obsługa klawiatury.}
Niskopoziomowa obsługa klawiatury przebiega następująco:
\begin{itemize}
\item Każde wciśnięcie i zwolnienie klawisza powoduje wygenerowanie przerwania
klawiatury.
\item Procedura obsługi tego przerwania rozpoznaje rodzaj zdarzenia,
odczytując jego kod - "scancode" - z odpowiedniego portu układu kontrolera
klawiatury (i8042).
\item Na podstawie scancode wyznaczany jest unikalny kod klawisza - "keycode".
\item Na podstawie kodu klawisza, przechowywanych w sterowniku informacji
o naciśniętych klawiszach specjalnych takich jak shift, alt i ctrl
oraz "keymapy" odwzorowującej te informacje w znak (ewentualnie ciąg znaków)
ASCII, wyznaczany jest wynik naciśnięcia klawisza w postaci, jakiej oczekuje
użytkownik.
\item Wynik z poprzedniego kroku przekazywany jest do aktywnej wirtualnej
konsoli oraz powiązanego z nią terminala poprzez procedurę
\texttt{vcons\_input\_[char/string]}.
\end{itemize}
\subsubsection{Obsługa karty graficznej.}
Niskopoziomowa komunikacja z kartą graficzną w Impali polega na:
\begin{itemize}
\item Początkowym zainicjalizowaniu karty graficznej, realizowanym poprzez
odpowiednią sekwencję zapisów i odczytów z portów karty. W kroku tym
ustawiany jest m.in. kursor sprzętowy. Ponieważ nie ma możliwości wyłączenia
migania kursora sprzętowego, zostaje on ukryty. Kursor widoczny na ekranie jest
emulowany programowo.
\item Bufor ramki karty graficznej jest odwzorowany w pamięć pod adresem fizycznym\\
\texttt{0xb8000}. Jako, że w Impali niskie adresy są zarezerwowane na przestrzeń
użytkownika, ten adres fizyczny jest z koleji odwzorowywany w stercie jądra.
Wyświetlenie znaku w pewnym miejscu ekranu polega na
zapisaniu go w odpowiednim miejscu pamięci. Atrybuty znaków takie jak ich kolor
dla znaku z komórki pamięci $x$ ustawiane są w komórce $x+1$.
\end{itemize}
\subsection{Emulacja terminala.}
Aby umożliwić programom użytkownika bardziej zaawansowaną kontrolę nad
zawartością ekranu, wirtualne konsole udają, że są fizycznym terminalem.
Konsola w Impali emuluje VT100, popularny terminal stworzony przez
firmę Digital Equipment Corporation. Emulacja ta polega na rozpoznawaniu
sekwencji sterujących tego terminala oraz odpowiednim reagowaniu na nie.
Podobnie, wejście z klawiatury przedstawiane jest użytkownikowi w postaci, jaką
by otrzymał pracując na terminalu VT100 i korzystając z jego klawiatury.

Dzięki takim działaniom progamy mają możliwość m.in. ustawiać pozycję kursora
na ekranie, przewijać ekran, kasować jego zawartość, pobierać informacje
o położeniu kursora i o wspieranych funkcjonalnościach, zmieniać tryb pracy
terminala i atrybuty wypisywanych znaków.
\begin{table}
\begin{tabular}{|l|l|}
\hline
ESC[2J & Czyści cały ekran \\
ESC3C & Przesuwa kursor o 3 pozycje w prawo \\
ESC[1;5H & Ustawia kursor w piątej kolumnie pierwszego wiersza \\
ESC[5;7;1m & Włącza mruganie, pogrubienie oraz zamienia kolor tła z kolorem znaku \\
ESC[6n & Żąda informacji o aktualnym położeniu kursora \\
\hline
\end{tabular}
\caption{Przykładowe sekwencje sterujące VT100. ESC oznacza znak \texttt{$\backslash$033}}
\end{table}

%można dać małą tabelkę z przykładowymi sekwencjami
\subsection{Termcap.}
Jako, że istnieje wiele terminali, różniących się sekwencjami
sterującymi, rozmiarem ekranu i innymi szczegółami ich działania, wynikła
potrzeba udostępniania procesowi informacji o terminalu na jakim aktualnie
działa. Identyfikator tego terminala przechowywany jest w zmiennej środowiskowej
\texttt{TERM}. Dostęp do informacji o konkretnych sekwencjach sterujących
możliwy jest poprzez następujące funkcje biblioteki C: \texttt{tgetstr},
\texttt{tgetnum}, \texttt{tgetflag}. Zanim jednak będziemy mogli skorzystać
z tych funkcji, konieczne jest załadowanie informacje o wybranym terminalu
za pomocą funkcji \texttt{tgetent}. Informacje uzyskane z wymienionych funkcji
mogą służyć jako wejście do procedury \texttt{tgoto}, wypełniającej sekwencję
sterującą o wymagane argumenty, oraz procedury \texttt{tputs} wysyłającej
sekwencję do terminala.

Baza danych dla termcap typowo przechowywana w pliku, jest u nas dostępna
jako wartość zmiennej środowiskowej \texttt{TERMCAP}.
