++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/ansi.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 

 00000	/* Заголовочный файл <ansi.h> помогает выяснить, достаточно ли компилятор совместим 
 00001	 * с стандартным языком C для MINIX, чтобы пользоваться им. Если совместимость достаточна,
 00002	 * определяется символ _ANSI, равный 31459. В противном случае _ANSI не определяется
 00003	 * здесь, однако может быть определен приложениями, желающими нарушить правила.
 00004	 * Магическое число в определении предназначено для противодействия ненужному нарушению
 00005	 * правил (для совместимости с тестами '#ifdef _ANSI" в заголовочных файлах _ANSI
 00006	 * следует определить как ничто, однако это вызовет сбой многих библиотечных
 00007	 * процедур, использующих "#if _ANSI".)
 00008	
 00009	 * Если символ _ANSI определен, определяется макрос
 00010	 *
 00011	 *      _PROTOTYPE(function, params)
 00012	 *
 00013	 * Он подставляется несколькими способами, по необходимости генерируя стандартные
 00014	 * прототипы ANSI C, либо устаревшие прототипы K&R (Kernighan & Ritchie)
 00015	 * Наконец, некоторые программы используют _CONST, _VOIDSTAR и т. п. так, что они
 00016	 * переносимы между компиляторами ANSI и K&R.
 00017	 * Соответствующие макросы определены здесь.
 00018	 */
 00019	
 00020	#ifndef _ANSI_H
 00021	#define _ANSI_H
 00022	
 00023	#if __STDC__ == 1
 00024	#define _ANSI           31459   /* компилятор полностью совместим с ANSI */
 00025	#endif
 00026	
 00027	#ifdef __GNUC__
 00028	#define _ANSI           31459   /* gcc достаточно совместим даже в режиме, не являющемся режимом ANSI */
 00029	#endif
 00030	
 00031	#ifdef _ANSI
 00032	
 00033	/* Все для прототипов ANSI. */
 00034	#define _PROTOTYPE(function, params)    function params
 00035	#define _ARGS(params)                   params
 00036	
 00037	#define _VOIDSTAR       void *
 00038	#define _VOID           void
 00039	#define _CONST          const
 00040	#define _VOLATILE       volatile
 00041	#define _SIZET          size_t
 00042	
 00043	#else
 00044	
 00045	/* Выбросить параметры для прототипов K&R. */
 00046	#define _PROTOTYPE(function, params)    function()
 00047	#define _ARGS(params)                   ()
 00048	
 00049	#define _VOIDSTAR       void *
 00050	#define _VOID           void
 00051	#define _CONST
 00052	#define _VOLATILE
 00053	#define _SIZET          int
 00054	
 00055	#endif /* _ANSI */
 00056	
 00057	/* Это должно быть определено как restrict при использовании компилятора C99 */
 00058	#define _RESTRICT
 00059	
 00060	/* Задание любого из символов _MINIX, _POSIX_C_SOURCE и _POSIX2_SOURCE подразумевает
 00061	 * _POSIX_SOURCE.  (это вряд ли правильно размещать в коде для ANSI.)
 00062	 */
 00063	#if defined(_MINIX) || _POSIX_C_SOURCE > 0 || defined(_POSIX2_SOURCE)
 00064	#undef _POSIX_SOURCE
 00065	#define _POSIX_SOURCE   1
 00066	#endif
 00067	
 00068	#endif /* ANSI_H */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/limits.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 00100	/* В заголовочном файле <limits.h> определены некоторые базовые размеры
 00101	 * как для типов данных (например, разрядность типа integer), так и для
 00102	 * операционной системы (например, число символов в имени файла).
 00103	 */
 00104	
 00105	#ifndef _LIMITS_H
 00106	#define _LIMITS_H
 00107	
 00108	/* Определения для типа char (в MINIX 8 бит, со знаком). */
 00109	#define CHAR_BIT           8    /* бит в char */
 00110	#define CHAR_MIN        -128    /* минимальное значение char */
 00111	#define CHAR_MAX         127    /* максимальное значение char */
 00112	#define SCHAR_MIN       -128    /* минимальное значение signed char */
 00113	#define SCHAR_MAX        127    /* максимальное значение signed char */
 00114	#define UCHAR_MAX        255    /* максимальное значение unsigned char */
 00115	#define MB_LEN_MAX         1    /* максимальное значение multibyte char */
 00116	
 00117	/* Определения для типа short (в MINIX 16 бит). */
 00118	#define SHRT_MIN  (-32767-1)    /* минимальное значение short */
 00119	#define SHRT_MAX       32767    /* максимальное значение short */
 00120	#define USHRT_MAX     0xFFFF    /* максимальное значение unsigned short */
 00121	
 00122	/* _EM_WSIZE – символ, генерируемый компилятором, размер слова в байтах */
 00123	#define INT_MIN (-2147483647-1) /* минимальное значение 32-разрядного типа int */
 00124	#define INT_MAX   2147483647    /* максимальное значение 32-разрядного типа int */
 00125	#define UINT_MAX  0xFFFFFFFF    /* максимальное значение 32-разрядного типа unsigned int */
 00126	
 00127	/*Определения для типа long (В MINIX – 32 бита). */
 00128	#define LONG_MIN (-2147483647L-1) /* минимальное значение типа long */
 00129	#define LONG_MAX  2147483647L    /* максимальное значение типа long */
 00130	#define ULONG_MAX 0xFFFFFFFFL    /* максимальное значение типа unsigned long */
 00131	
 00132	#include <sys/dir.h>
 00133	
 00134	/* Минимальные значения, требуемые стандартом POSIX P1003.1 (таблица 2-3) */
 00135	#ifdef _POSIX_SOURCE            /* видимы только для POSIX */
 00136	#define _POSIX_ARG_MAX    4096  /* exec() может иметь 4K аргументов */
 00137	#define _POSIX_CHILD_MAX     6  /* процесс может иметь 6 потомков */
 00138	#define _POSIX_LINK_MAX      8  /* файл может иметь 8 связей */
 00139	#define _POSIX_MAX_CANON   255  /* размер канонической входной очереди */
 00140	#define _POSIX_MAX_INPUT   255  /* можно хранить 255 введенных символов */
 00141	#define _POSIX_NAME_MAX DIRSIZ  /* имя файла может включать 14 символов */
 00142	#define _POSIX_NGROUPS_MAX   0  /* дополнительные ID группы необязательны */
 00143	#define _POSIX_OPEN_MAX     16  /* процесс может открыть 16 файлов */
 00144	#define _POSIX_PATH_MAX    255  /* путь может включать 255 символов */
 00145	#define _POSIX_PIPE_BUF    512  /* запись в канал не должна быть менее 512 байт */
 00146	#define _POSIX_STREAM_MAX    8  /* как минимум 8 файлов можно открыть одновременно */
 00147	#define _POSIX_TZNAME_MAX    3  /* имена временных зон должны быть не менее 3 символов */
 00148	#define _POSIX_SSIZE_MAX 32767  /* read() должна поддерживать чтение 32767 байт */
 00149	
 00150	/* Значения, фактически реализованные в MINIX (таблицы 2-4, 2-5, 2-6 и 2-7). */
 00151	/* Некоторые из этих устаревших имен лучше было бы определить не в коде для POSIX. */
 00152	#define _NO_LIMIT          100  /* произвольное число; предел не регламентирован */
 00153	
 00154	#define NGROUPS_MAX          0  /* дополнительные ID групп недоступны */
 00155	#define ARG_MAX          16384  /* число байт аргументов + окружение для exec() */
 00156	#define CHILD_MAX    _NO_LIMIT  /* MINIX не ограничивает потомков */
 00157	#define OPEN_MAX            20  /* число файлов, которое может открыть процесс */
 00158	#define LINK_MAX      SHRT_MAX  /* число связей файла */
 00159	#define MAX_CANON          255  /* размер канонической входной очереди */
 00160	#define MAX_INPUT          255  /* размер буфера опережающего ввода */
 00161	#define NAME_MAX        DIRSIZ  /* число символов в имени файла */
 00162	#define PATH_MAX           255  /* число символов в пути */
 00163	#define PIPE_BUF          7168  /* минимальное число байтов при записи в канал */
 00164	#define STREAM_MAX          20  /* должно быть равным FOPEN_MAX в stdio.h */
 00165	#define TZNAME_MAX           3  /* максимальное число байтов в имени временной зоны равно 3 */
 00166	#define SSIZE_MAX        32767  /* максимальное значение счетчика байтов для read() */
 00167	
 00168	#endif /* _POSIX_SOURCE */
 00169	
 00170	#endif /* _LIMITS_H */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/errno.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 00200	/* В заголовочном файле <errno.h> определены коды различных ошибок, которые могут
 00201	 * возникать при исполнении программ. Они видимы для программ пользователя и должны
 00202	 * представлять собой небольшие положительные целые числа. Тем не менее, они также
 00203	 * используются и внутри MINIX, где они должны быть отрицательными. Например, системный
 00204	 * вызов READ исполняется внутренне путем обращения к do_read().Эта функция
 00205	 * возвращает либо положительное число считанных байтов, либо отрицательный код ошибки.
 00206	 *
 00207	 * Чтобы разрешить проблему кодов ошибок, которые должны быть отрицательными внутри
 00208	 * системы и положительными вне ее, используется следующий механизм.
 00209	 * Все определения имеют вид
 00210	 *
 00211	 *      #define EPERM           (_SIGN 1)
 00212	 *
  
 00213	 * Если макрос _SYSTEM определен, то _SIGN задается равным "-", в противном случае он
 00214	 * задается равным "". Таким образом, при компиляции операционной системы макрос
 00215	 * _SYSTEM будет определен и EPERM получит значение (- 1), а при включении этого
 00216	 * файла в обычную пользовательскую программу EPERM будет равен (1).
 00217	 */
 00218	
 00219	#ifndef _ERRNO_H                /* проверка, не включен ли заголовок <errno.h> ранее */
 00220	#define _ERRNO_H                /* нет, не включен; учесть этот факт */
 00221	
 00222	/* Определение _SIGN как "" или "-" в зависимости от _SYSTEM. */
 00223	#ifdef _SYSTEM
 00224	#   define _SIGN         -
 00225	#   define OK            0
 00226	#else
 00227	#   define _SIGN         
 00228	#endif
 00229	
 00230	extern int errno;                 /* сюда помещаются коды ошибок */
 00231	
 00232	/* Численные значения кодов ошибок */
 00233	#define _NERROR               70  /* количество ошибок */  
 00234	
 00235	#define EGENERIC      (_SIGN 99)  /* общая ошибка */
 00236	#define EPERM         (_SIGN  1)  /* операция не разрешена */
 00237	#define ENOENT        (_SIGN  2)  /* файл или каталог не существует */
 00238	#define ESRCH         (_SIGN  3)  /* процесс не существует */
 00239	#define EINTR         (_SIGN  4)  /* вызов прерванной функции */
 00240	#define EIO           (_SIGN  5)  /* ошибка ввода-вывода */
 00241	#define ENXIO         (_SIGN  6)  /* устройство или адрес не существует */
 00242	#define E2BIG         (_SIGN  7)  /* слишком длинный список аргументов */
 00243	#define ENOEXEC       (_SIGN  8)  /* ошибка формата exec */
 00244	#define EBADF         (_SIGN  9)  /* некорректный дескриптор файла */
 00245	#define ECHILD        (_SIGN 10)  /* процесс-потомок отсутствует */
 00246	#define EAGAIN        (_SIGN 11)  /* ресурс временно недоступен */
 00247	#define ENOMEM        (_SIGN 12)  /* недостаточно памяти */
 00248	#define EACCES        (_SIGN 13)  /* разрешение отклонено */
 00249	#define EFAULT        (_SIGN 14)  /* некорректный адрес */
 00250	#define ENOTBLK       (_SIGN 15)  /* расширение: не блочный специальный файл */
 00251	#define EBUSY         (_SIGN 16)  /* ресурс занят */
 00252	#define EEXIST        (_SIGN 17)  /* файл существует */
 00253	#define EXDEV         (_SIGN 18)  /* некорректная связь */
 00254	#define ENODEV        (_SIGN 19)  /* устройство не существует */
 00255	#define ENOTDIR       (_SIGN 20)  /* не является каталогом */
 00256	#define EISDIR        (_SIGN 21)  /* является каталогом */
 00257	#define EINVAL        (_SIGN 22)  /* некорректный аргумент */
 00258	#define ENFILE        (_SIGN 23)  /* в системе слишком много открытых файлов */
 00259	#define EMFILE        (_SIGN 24)  /* слишком много открытых файлов */
 00260	#define ENOTTY        (_SIGN 25)  /* некорректная операция управления вводом-выводом */
 00261	#define ETXTBSY       (_SIGN 26)  /* больше не используется */
 00262	#define EFBIG         (_SIGN 27)  /* файл слишком велик */
 00263	#define ENOSPC        (_SIGN 28)  /* на устройстве не осталось свободного места */
 00264	#define ESPIPE        (_SIGN 29)  /* некорректная операция seek */
 00265	#define EROFS         (_SIGN 30)  /* файловая система только для чтения */
 00266	#define EMLINK        (_SIGN 31)  /* слишком много связей */
 00267	#define EPIPE         (_SIGN 32)  /* канал разорван */
 00268	#define EDOM          (_SIGN 33)  /* ошибка домена (из стандарта ANSI C) */
 00269	#define ERANGE        (_SIGN 34)  /* результат слишком велик (из стандарта ANSI C) */
 00270	#define EDEADLK       (_SIGN 35)  /* взаимная блокировка для ресурса преодолена */
 00271	#define ENAMETOOLONG  (_SIGN 36)  /* слишком длинное имя файла */
 00272	#define ENOLCK        (_SIGN 37)  /* блокировка недоступна */
 00273	#define ENOSYS        (_SIGN 38)  /* функция не реализована */
 00274	#define ENOTEMPTY     (_SIGN 39)  /* каталог не пуст */
 00275	
 00276	/* Ошибки, относящиеся к сети */
 00277	#define EPACKSIZE     (_SIGN 50)  /* некорректный размер пакета для протокола */
 00278	#define EOUTOFBUFS    (_SIGN 51)  /* осталось недостаточно буферов */
 00279	#define EBADIOCTL     (_SIGN 52)  /* недопустимое значение ioctl для устройства */
 00280	#define EBADMODE      (_SIGN 53)  /* некорректный режим в ioctl */
 00281	#define EWOULDBLOCK   (_SIGN 54)
 00282	#define EBADDEST      (_SIGN 55)  /* некорректный адрес назначения */
 00283	#define EDSTNOTRCH    (_SIGN 56)  /* приемник недоступен */
 00284	#define EISCONN       (_SIGN 57)  /* все готово к подключению */
 00285	#define EADDRINUSE    (_SIGN 58)  /* адрес используется */
 00286	#define ECONNREFUSED  (_SIGN 59)  /* отказ в соединении */
 00287	#define ECONNRESET    (_SIGN 60)  /* сброс подключения */
 00288	#define ETIMEDOUT     (_SIGN 61)  /* истек интервал ожидания */
 00289	#define EURG          (_SIGN 62)  /* наличие ожидающих данных */
 00290	#define ENOURG        (_SIGN 63)  /* ожидающих данных нет */
 00291	#define ENOTCONN      (_SIGN 64)  /* подключение отсутствует (еще или уже) */
 00292	#define ESHUTDOWN     (_SIGN 65)  /* вызов write для завершенного соединения */
 00293	#define ENOCONN       (_SIGN 66)  /* соединение не существует */
 00294	#define EAFNOSUPPORT  (_SIGN 67)  /* семейство адресов не поддерживается */
 00295	#define EPROTONOSUPPORT (_SIGN 68) /* протокол не поддерживается AF */
 00296	#define EPROTOTYPE    (_SIGN 69)  /* неподходящий тип протокола для сокета */
 00297	#define EINPROGRESS   (_SIGN 70)  /* операция выполняется */
 00298	#define EADDRNOTAVAIL (_SIGN 71)  /* невозможно назначить запрошенный адрес */
 00299	#define EALREADY      (_SIGN 72)  /* установка соединения выполняется */
 00300	#define EMSGSIZE      (_SIGN 73)  /* слишком длинное сообщение */
 00301	
 00302	/* Следующие ошибки не принадлежат стандарту POSIX, однако могут иметь место. 
 00303	 * Все они генерируются ядром и связаны с передачей сообщений.
 00304	 */
 00305	#define ELOCKED      (_SIGN 101)  /* передача сообщения невозможна из-за взаимной блокировки */
 00306	#define EBADCALL     (_SIGN 102)  /* недопустимый номер системного вызова */
 00307	#define EBADSRCDST   (_SIGN 103)  /* недопустимый приемник или источник */
 00308	#define ECALLDENIED  (_SIGN 104)  /* системный вызов не разрешен */
 00309	#define EDEADDST     (_SIGN 105)  /* приемник не существует */
 00310	#define ENOTREADY    (_SIGN 106)  /* источник или приемник не готов */
 00311	#define EBADREQUEST  (_SIGN 107)  /* приемник не может обработать запрос */
 00312	#define EDONTREPLY   (_SIGN 201)  /* псевдокод: не отсылать ответ */
 00313	
 00314	#endif /* _ERRNO_H */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/unistd.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 00400	/* Заголовочный файл <unistd.h> содержит несколько макроконстант. */
 00401	
 00402	#ifndef _UNISTD_H
 00403	#define _UNISTD_H
 00404	
 00405	#ifndef _TYPES_H
 00406	#include <sys/types.h>
 00407	#endif
 00408	
 00409	/* Значения, используемые access().  POSIX, таблица 2-8. */
 00410	#define F_OK               0    /* проверка существования файла */
 00411	#define X_OK               1    /* проверка, является ли файл исполняемым */
 00412	#define W_OK               2    /* проверка, можно ли записывать в файл */
 00413	#define R_OK               4    /* проверка, можно ли читать из файла */
 00414	
 00415	/* значения, определяющие положение в lseek(fd, offset, whence).  POSIX, таблица 2-9. */
 00416	#define SEEK_SET           0    /* смещение абсолютное  */
 00417	#define SEEK_CUR           1    /* смещение относительно текущей позиции */
 00418	#define SEEK_END           2    /* смещение относительно конца файла */
 00419	
 00420	/* Это значение требуется согласно POSIX, таблица 2-10. */
 00421	#define _POSIX_VERSION 199009L  /* версия соблюдаемого стандарта */
 00422	
 00423	/* Три определения, требуемые стандартом POSIX Sec. 8.2.1.2. */
 00424	#define STDIN_FILENO       0    /* дескриптор файла stdin */
 00425	#define STDOUT_FILENO      1    /* дескриптор файла stdout */
 00426	#define STDERR_FILENO      2    /* дескриптор файла stderr */
 00427	
 00428	#ifdef _MINIX
 00429	/* Выход из системы и остановка серверного процесса. */
 00430	#define RBT_HALT           0
 00431	#define RBT_REBOOT         1
 00432	#define RBT_PANIC          2    /* сбой сервера */
 00433	#define RBT_MONITOR        3    /* поручение действия монитору */
 00434	#define RBT_RESET          4    /* жесткая перезагрузка системы */
 00435	#endif
 00436	
 00437	/* Системная информация, получаемая вызовом sysgetinfo(). */
 00438	#define SI_KINFO           0    /* получение информации ядра через PM */
 00439	#define SI_PROC_ADDR       1    /* адрес таблицы процессов */
 00440	#define SI_PROC_TAB        2    /* копия всей таблицы процессов */
 00441	#define SI_DMAP_TAB        3    /* получение соответствий устройств и драйверов */
 00442	
 00443	/* Значение NULL должно быть определено в <unistd.h> согласно POSIX Sec. 2.7.1. */
 00444	#define NULL    ((void *)0)
 00445	
 00446	/* Конфигурируемые системные переменные. POSIX, таблица 4-2. */
 00447	#define _SC_ARG_MAX        1
 00448	#define _SC_CHILD_MAX      2
 00449	#define _SC_CLOCKS_PER_SEC 3
 00450	#define _SC_CLK_TCK        3
 00451	#define _SC_NGROUPS_MAX    4
 00452	#define _SC_OPEN_MAX       5
 00453	#define _SC_JOB_CONTROL    6
 00454	#define _SC_SAVED_IDS      7
 00455	#define _SC_VERSION        8
 00456	#define _SC_STREAM_MAX     9
 00457	#define _SC_TZNAME_MAX    10
 00458	
 00459	/* конфигурируемые переменные пути. POSIX, таблица 5-2. */
 00460	#define _PC_LINK_MAX       1    /* счетчик связей */
 00461	#define _PC_MAX_CANON      2    /* размер канонической входной очереди */
 00462	#define _PC_MAX_INPUT      3    /* буфер клавиатуры */
 00463	#define _PC_NAME_MAX       4    /* размер имени файла */
 00464	#define _PC_PATH_MAX       5    /* размер пути */
 00465	#define _PC_PIPE_BUF       6    /* размер канала */
 00466	#define _PC_NO_TRUNC       7    /* обработка компонентов с длинными именами */
 00467	#define _PC_VDISABLE       8    /* отключение терминала */
 00468	#define _PC_CHOWN_RESTRICTED 9  /* наличие или отсутствие ограничений для chown */
 00469	
 00470	/* POSIX определяет ряд возможностей, реализация которых выполняется по желанию конструктора
 00471	 * Конструктор имеет следующий выбор: 
 00472	 *
 00473	 * _POSIX_JOB_CONTROL       не определен:         контроль задач не реализован
 00474	 * _POSIX_SAVED_IDS         не определен:         uid/gid не сохраняются
 00475	 * _POSIX_NO_TRUNC          определен равным -1:  длинные пути усекаются
 00476	 * _POSIX_CHOWN_RESTRICTED  определен:            нельзя "дарить" файлы
 00477	 * _POSIX_VDISABLE          определен:            функции терминала можно отключить
 00478	 */
 00479	#define _POSIX_NO_TRUNC       (-1)
 00480	#define _POSIX_CHOWN_RESTRICTED  1
 00481	
 00482	/* Прототипы функций. */
 00483	_PROTOTYPE( void _exit, (int _status)                                   );
 00484	_PROTOTYPE( int access, (const char *_path, int _amode)                 );
 00485	_PROTOTYPE( unsigned int alarm, (unsigned int _seconds)                 );
 00486	_PROTOTYPE( int chdir, (const char *_path)                              );
 00487	_PROTOTYPE( int fchdir, (int fd)                                        );
 00488	_PROTOTYPE( int chown, (const char *_path, _mnx_Uid_t _owner, _mnx_Gid_t _group)        );
 00489	_PROTOTYPE( int close, (int _fd)                                        );
 00490	_PROTOTYPE( char *ctermid, (char *_s)                                   );
 00491	_PROTOTYPE( char *cuserid, (char *_s)                                   );
 00492	_PROTOTYPE( int dup, (int _fd)                                          );
 00493	_PROTOTYPE( int dup2, (int _fd, int _fd2)                               );
 00494	_PROTOTYPE( int execl, (const char *_path, const char *_arg, ...)       );
 00495	_PROTOTYPE( int execle, (const char *_path, const char *_arg, ...)      );
 00496	_PROTOTYPE( int execlp, (const char *_file, const char *arg, ...)       );
 00497	_PROTOTYPE( int execv, (const char *_path, char *const _argv[])         );
 00498	_PROTOTYPE( int execve, (const char *_path, char *const _argv[], 
 00499	                                                char *const _envp[])    );
 00500	_PROTOTYPE( int execvp, (const char *_file, char *const _argv[])        );
 00501	_PROTOTYPE( pid_t fork, (void)                                          );
 00502	_PROTOTYPE( long fpathconf, (int _fd, int _name)                        );
 00503	_PROTOTYPE( char *getcwd, (char *_buf, size_t _size)                    );
 00504	_PROTOTYPE( gid_t getegid, (void)                                       );
 00505	_PROTOTYPE( uid_t geteuid, (void)                                       );
 00506	_PROTOTYPE( gid_t getgid, (void)                                        );
 00507	_PROTOTYPE( int getgroups, (int _gidsetsize, gid_t _grouplist[])        );
 00508	_PROTOTYPE( char *getlogin, (void)                                      );
 00509	_PROTOTYPE( pid_t getpgrp, (void)                                       );
 00510	_PROTOTYPE( pid_t getpid, (void)                                        );
 00511	_PROTOTYPE( pid_t getppid, (void)                                       );
 00512	_PROTOTYPE( uid_t getuid, (void)                                        );
 00513	_PROTOTYPE( int isatty, (int _fd)                                       );
 00514	_PROTOTYPE( int link, (const char *_existing, const char *_new)         );
 00515	_PROTOTYPE( off_t lseek, (int _fd, off_t _offset, int _whence)          );
 00516	_PROTOTYPE( long pathconf, (const char *_path, int _name)               );
 00517	_PROTOTYPE( int pause, (void)                                           );
 00518	_PROTOTYPE( int pipe, (int _fildes[2])                                  );
 00519	_PROTOTYPE( ssize_t read, (int _fd, void *_buf, size_t _n)              );
 00520	_PROTOTYPE( int rmdir, (const char *_path)                              );
 00521	_PROTOTYPE( int setgid, (_mnx_Gid_t _gid)                               );
 00522	_PROTOTYPE( int setpgid, (pid_t _pid, pid_t _pgid)                      );
 00523	_PROTOTYPE( pid_t setsid, (void)                                        );
 00524	_PROTOTYPE( int setuid, (_mnx_Uid_t _uid)                               );
 00525	_PROTOTYPE( unsigned int sleep, (unsigned int _seconds)                 );
 00526	_PROTOTYPE( long sysconf, (int _name)                                   );
 00527	_PROTOTYPE( pid_t tcgetpgrp, (int _fd)                                  );
 00528	_PROTOTYPE( int tcsetpgrp, (int _fd, pid_t _pgrp_id)                    );
 00529	_PROTOTYPE( char *ttyname, (int _fd)                                    );
 00530	_PROTOTYPE( int unlink, (const char *_path)                             );
 00531	_PROTOTYPE( ssize_t write, (int _fd, const void *_buf, size_t _n)       );
 00532	
 00533	/* Open Group Base Specifications Issue 6 (не завершено) */
 00534	_PROTOTYPE( int symlink, (const char *path1, const char *path2)         );
 00535	_PROTOTYPE( int getopt, (int _argc, char **_argv, char *_opts)          );
 00536	extern char *optarg;
 00537	extern int optind, opterr, optopt;
 00538	_PROTOTYPE( int usleep, (useconds_t _useconds)                          );
 00539	
 00540	#ifdef _MINIX
 00541	#ifndef _TYPE_H
 00542	#include <minix/type.h>
 00543	#endif
 00544	_PROTOTYPE( int brk, (char *_addr)                                      );
 00545	_PROTOTYPE( int chroot, (const char *_name)                             );
 00546	_PROTOTYPE( int mknod, (const char *_name, _mnx_Mode_t _mode, Dev_t _addr)      );
 00547	_PROTOTYPE( int mknod4, (const char *_name, _mnx_Mode_t _mode, Dev_t _addr,
 00548	            long _size)                                                 );
 00549	_PROTOTYPE( char *mktemp, (char *_template)                             );
 00550	_PROTOTYPE( int mount, (char *_spec, char *_name, int _flag)            );
 00551	_PROTOTYPE( long ptrace, (int _req, pid_t _pid, long _addr, long _data) );
 00552	_PROTOTYPE( char *sbrk, (int _incr)                                     );
 00553	_PROTOTYPE( int sync, (void)                                            );
 00554	_PROTOTYPE( int fsync, (int fd)                                         );
 00555	_PROTOTYPE( int umount, (const char *_name)                             );
 00556	_PROTOTYPE( int reboot, (int _how, ...)                                 );
 00557	_PROTOTYPE( int gethostname, (char *_hostname, size_t _len)             );
 00558	_PROTOTYPE( int getdomainname, (char *_domain, size_t _len)             );
 00559	_PROTOTYPE( int ttyslot, (void)                                         );
 00560	_PROTOTYPE( int fttyslot, (int _fd)                                     );
 00561	_PROTOTYPE( char *crypt, (const char *_key, const char *_salt)          );
 00562	_PROTOTYPE( int getsysinfo, (int who, int what, void *where)            );
 00563	_PROTOTYPE( int getprocnr, (void)                                       );
 00564	_PROTOTYPE( int findproc, (char *proc_name, int *proc_nr)               );
 00565	_PROTOTYPE( int allocmem, (phys_bytes size, phys_bytes *base)           );
 00566	_PROTOTYPE( int freemem, (phys_bytes size, phys_bytes base)             );
 00567	#define DEV_MAP 1
 00568	#define DEV_UNMAP 2
 00569	#define mapdriver(driver, device, style) devctl(DEV_MAP, driver, device, style)
 00570	#define unmapdriver(device) devctl(DEV_UNMAP, 0, device, 0)
 00571	_PROTOTYPE( int devctl, (int ctl_req, int driver, int device, int style));
 00572	
 00573	/* Для совместимости с другими системами Unix */
 00574	_PROTOTYPE( int getpagesize, (void)                                     );
 00575	_PROTOTYPE( int setgroups, (int ngroups, const gid_t *gidset)           );
 00576	
 00577	#endif
 00578	
 00579	_PROTOTYPE( int readlink, (const char *, char *, int));
 00580	_PROTOTYPE( int getopt, (int, char **, char *));
 00581	extern int optind, opterr, optopt;
 00582	
 00583	#endif /* _UNISTD_H */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/string.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 00600	/* Заголовочный файл <string.h> содержит прототипы функций
 00601	 * обработки строк.
 00602	 */
 00603	
 00604	#ifndef _STRING_H
 00605	#define _STRING_H
 00606	
 00607	#define NULL    ((void *)0)
 00608	
 00609	#ifndef _SIZE_T
 00610	#define _SIZE_T
 00611	typedef unsigned int size_t;    /* тип, возвращаемый sizeof */
 00612	#endif /*_SIZE_T */
 00613	
 00614	/* Прототипы функций. */
 00615	#ifndef _ANSI_H
 00616	#include <ansi.h>
 00617	#endif
 00618	
 00619	_PROTOTYPE( void *memchr, (const void *_s, int _c, size_t _n)           );
 00620	_PROTOTYPE( int memcmp, (const void *_s1, const void *_s2, size_t _n)   );
 00621	_PROTOTYPE( void *memcpy, (void *_s1, const void *_s2, size_t _n)       );
 00622	_PROTOTYPE( void *memmove, (void *_s1, const void *_s2, size_t _n)      );
 00623	_PROTOTYPE( void *memset, (void *_s, int _c, size_t _n)                 );
 00624	_PROTOTYPE( char *strcat, (char *_s1, const char *_s2)                  );
 00625	_PROTOTYPE( char *strchr, (const char *_s, int _c)                      );
 00626	_PROTOTYPE( int strncmp, (const char *_s1, const char *_s2, size_t _n)  );
 00627	_PROTOTYPE( int strcmp, (const char *_s1, const char *_s2)              );
 00628	_PROTOTYPE( int strcoll, (const char *_s1, const char *_s2)             );
 00629	_PROTOTYPE( char *strcpy, (char *_s1, const char *_s2)                  );
 00630	_PROTOTYPE( size_t strcspn, (const char *_s1, const char *_s2)          );
 00631	_PROTOTYPE( char *strerror, (int _errnum)                               );
 00632	_PROTOTYPE( size_t strlen, (const char *_s)                             );
 00633	_PROTOTYPE( char *strncat, (char *_s1, const char *_s2, size_t _n)      );
 00634	_PROTOTYPE( char *strncpy, (char *_s1, const char *_s2, size_t _n)      );
 00635	_PROTOTYPE( char *strpbrk, (const char *_s1, const char *_s2)           );
 00636	_PROTOTYPE( char *strrchr, (const char *_s, int _c)                     );
 00637	_PROTOTYPE( size_t strspn, (const char *_s1, const char *_s2)           );
 00638	_PROTOTYPE( char *strstr, (const char *_s1, const char *_s2)            );
 00639	_PROTOTYPE( char *strtok, (char *_s1, const char *_s2)                  );
 00640	_PROTOTYPE( size_t strxfrm, (char *_s1, const char *_s2, size_t _n)     );
 00641	
 00642	#ifdef _POSIX_SOURCE
 00643	/* Спецификации Open Group Base Issue 6 (не завершено) */
 00644	 char *strdup(const char *_s1);
 00645	#endif
 00646	
 00647	#ifdef _MINIX
 00648	/* Для обратной совместимости. */
 00649	_PROTOTYPE( char *index, (const char *_s, int _charwanted)              );
 00650	_PROTOTYPE( char *rindex, (const char *_s, int _charwanted)             );
 00651	_PROTOTYPE( void bcopy, (const void *_src, void *_dst, size_t _length)  );
 00652	_PROTOTYPE( int bcmp, (const void *_s1, const void *_s2, size_t _length));
 00653	_PROTOTYPE( void bzero, (void *_dst, size_t _length)                    );
 00654	_PROTOTYPE( void *memccpy, (char *_dst, const char *_src, int _ucharstop,
 00655	                                                    size_t _size)       );
 00656	
 00657	/* Различные дополнительные функции */
 00658	_PROTOTYPE( int strcasecmp, (const char *_s1, const char *_s2)          );
 00659	_PROTOTYPE( int strncasecmp, (const char *_s1, const char *_s2,
 00660	                                                        size_t _len)    );
 00661	_PROTOTYPE( size_t strnlen, (const char *_s, size_t _n)                 );
 00662	#endif
 00663	
 00664	#endif /* _STRING_H */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/signal.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 00700	/* Заголовочный файл <signal.h> определяет все сигналы ANSI и POSIX.
 00701	 * MINIX поддерживает все сигналы, требуемые POSIX. Они определены далее.
 00702	 * Поддерживаются также некоторые дополнительные сигналы.
 00703	 */
 00704	
 00705	#ifndef _SIGNAL_H
 00706	#define _SIGNAL_H
 00707	
 00708	#ifndef _ANSI_H
 00709	#include <ansi.h>
 00710	#endif
 00711	#ifdef _POSIX_SOURCE
 00712	#ifndef _TYPES_H
 00713	#include <sys/types.h>
 00714	#endif
 00715	#endif
 00716	
 00717	/* Типы, тесно связанные с обработкой сигналов. */
 00718	typedef int sig_atomic_t;
 00719	
 00720	#ifdef _POSIX_SOURCE
 00721	#ifndef _SIGSET_T
 00722	#define _SIGSET_T
 00723	typedef unsigned long sigset_t;
 00724	#endif
 00725	#endif
 00726	
 00727	#define _NSIG             20    /* число используемых сигналов */
 00728	
 00729	#define SIGHUP             1    /* отбой */
 00730	#define SIGINT             2    /* прерывание (DEL) */
 00731	#define SIGQUIT            3    /* завершение (ASCII FS) */
 00732	#define SIGILL             4    /* недопустимая инструкция */
 00733	#define SIGTRAP            5    /* прерывание трассировки (не сбрасывать при обработке) */
 00734	#define SIGABRT            6    /* Аномальное завершение */
 00735	#define SIGIOT             6    /* SIGABRT для тех, кто используюет PDP-11 */
 00736	#define SIGUNUSED          7    /* резервный код */
 00737	#define SIGFPE             8    /* исключение при операциях над вещественными числами */
 00738	#define SIGKILL            9    /* принудительное завершение (сигнал не может быть игнорирован или обработан) */
 00739	#define SIGUSR1           10    /* задаваемый пользователем сигнал № 1 */
 00740	#define SIGSEGV           11    /* нарушение целостности памяти */
 00741	#define SIGUSR2           12    /* задаваемый пользователем сигнал № 2 */
 00742	#define SIGPIPE           13    /* запись в канал, из которого никто не читает */
 00743	#define SIGALRM           14    /* сигнал таймера */
 00744	#define SIGTERM           15    /* сигнал завершения программы */
 00745	#define SIGCHLD           17    /* дочерний процесс завершил работу или остановился */
 00746	
 00747	#define SIGEMT             7    /* устарело */
 00748	#define SIGBUS            10    /* устарело */
 00749	
 00750	/* Сигналы, специфичные для MINIX. Они применяются для информирования системных процессов
 00751	 * (например, менеджера процессов) о системных событиях.
 00752	 */
 00753	#define SIGKMESS          18    /* новое сообщение ядра */
 00754	#define SIGKSIG           19    /* ожидание сигнала ядра */
 00755	#define SIGKSTOP          20    /* завершение ядра */
 00756	
 00757	/* POSIX требует определения следующих сигналов, даже если они не поддерживаются.
 00758	 * Такие сигналы определены далее.
 00759	 */
 00760	#define SIGCONT           18    /* продолжить, если остановлен */
 00761	#define SIGSTOP           19    /* стоп */
 00762	#define SIGTSTP           20    /* интерактивная остановка */
 00763	#define SIGTTIN           21    /* фоновый процесс собирается выполнить чтение */
 00764	#define SIGTTOU           22    /* фоновый процесс собирается выполнить запись */
 00765	
 00766	/* Тип sighandler_t не разрешен, если не определен _POSIX_SOURCE. */
 00767	typedef void _PROTOTYPE( (*__sighandler_t), (int) );
 00768	
 00769	/* Макросы, используемые как указатели на функции. */
 00770	#define SIG_ERR    ((__sighandler_t) -1)        /* возврат ошибки */
 00771	#define SIG_DFL    ((__sighandler_t)  0)        /* обработка сигнала по умолчанию */
 00772	#define SIG_IGN    ((__sighandler_t)  1)        /* игнорировать сигнал */
 00773	#define SIG_HOLD   ((__sighandler_t)  2)        /* блокировать сигнал */
 00774	#define SIG_CATCH  ((__sighandler_t)  3)        /* обработать сигнал */
 00775	#define SIG_MESS   ((__sighandler_t)  4)        /* передать как сообщение (MINIX) */
 00776	
 00777	#ifdef _POSIX_SOURCE
 00778	struct sigaction {
 00779	  __sighandler_t sa_handler;    /* SIG_DFL, SIG_IGN или указатель на функцию */
 00780	  sigset_t sa_mask;             /* сигналы, которые должны быть блокированы в обработчике */
 00781	  int sa_flags;                 /* специальные флаги*/
 00782	};
 00783	
 00784	/* Поля sa_flags. */
 00785	#define SA_ONSTACK   0x0001     /* доставка сигнала в альтернативный стек */
 00786	#define SA_RESETHAND 0x0002     /* переустановить обработчик при перехвате сигнала */
 00787	#define SA_NODEFER   0x0004     /* не блокировать сигнал при перехвате */
 00788	#define SA_RESTART   0x0008     /* автоматический перезапуск системного вызова */
 00789	#define SA_SIGINFO   0x0010     /* расширенная обработка сигнала */
 00790	#define SA_NOCLDWAIT 0x0020     /* не создавать зомби */
 00791	#define SA_NOCLDSTOP 0x0040     /* не принимать SIGCHLD при остановке дочернего процесса */
 00792	
 00793	/* Эти значения требуются POSIX для использования в системном вызове sigprocmask(2). */
 00794	#define SIG_BLOCK          0    /* для блокирования сигналов */
 00795	#define SIG_UNBLOCK        1    /* для разблокирования сигналов */
 00796	#define SIG_SETMASK        2    /* для задания маски сигналов */
 00797	#define SIG_INQUIRE        4    /* только для внутреннего использования */
 00798	#endif  /* _POSIX_SOURCE */
 00799	
 00800	/* Прототипы функций POSIX и ANSI. */
 00801	_PROTOTYPE( int raise, (int _sig)                                       );
 00802	_PROTOTYPE( __sighandler_t signal, (int _sig, __sighandler_t _func)     );
 00803	
 00804	#ifdef _POSIX_SOURCE
 00805	_PROTOTYPE( int kill, (pid_t _pid, int _sig)                            );
 00806	_PROTOTYPE( int sigaction,
 00807	    (int _sig, const struct sigaction *_act, struct sigaction *_oact)   );
 00808	_PROTOTYPE( int sigaddset, (sigset_t *_set, int _sig)                   );
 00809	_PROTOTYPE( int sigdelset, (sigset_t *_set, int _sig)                   );
 00810	_PROTOTYPE( int sigemptyset, (sigset_t *_set)                           );
 00811	_PROTOTYPE( int sigfillset, (sigset_t *_set)                            );
 00812	_PROTOTYPE( int sigismember, (const sigset_t *_set, int _sig)           );
 00813	_PROTOTYPE( int sigpending, (sigset_t *_set)                            );
 00814	_PROTOTYPE( int sigprocmask,
 00815	            (int _how, const sigset_t *_set, sigset_t *_oset)           );
 00816	_PROTOTYPE( int sigsuspend, (const sigset_t *_sigmask)                  );
 00817	#endif
 00818	
 00819	#endif /* _SIGNAL_H */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/fcntl.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 00900	/* Заголовочный файл <fcntl.h> необходим системным вызовам open() и fcntl(),
 00901	 * имеющим множество параметров и флагов. Они описаны здесь.  
 00902	 * Форматы вызовов следующие: 
 00903	 *
 00904	 *      open(path, oflag [,mode])       открытие файла
 00905	 *      fcntl(fd, cmd [,arg])           установка или считывание атрибутов файла
 00906	 * 
 00907	 */
 00908	
 00909	#ifndef _FCNTL_H
 00910	#define _FCNTL_H
 00911	
 00912	#ifndef _TYPES_H
 00913	#include <sys/types.h>
 00914	#endif
 00915	
 00916	/* Эти значения используются для аргумента cmd в fcntl().  POSIX, таблица 6-1.  */
 00917	#define F_DUPFD            0    /* дублирование дескриптора файла */
 00918	#define F_GETFD            1    /* считывание флагов дескриптора файла*/
 00919	#define F_SETFD            2    /* установка флагов дескриптора файла */
 00920	#define F_GETFL            3    /* считывание флагов состояния файла */
 00921	#define F_SETFL            4    /* установка флагов состояния файла */
 00922	#define F_GETLK            5    /* считывание информации блокирования записи */
 00923	#define F_SETLK            6    /* установка информации блокирования записи */
 00924	#define F_SETLKW           7    /* установка информации блокирования записи; ожидание в случае блокирования */
 00925	
 00926	/* Флаги дескриптора файла, используемые в fcntl().  POSIX, таблица 6-2. */
 00927	#define FD_CLOEXEC         1    /* закрытие при exec, третий аргумент fcntl */
 00928	
 00929	/* Значения L_type для блокирования записи с помощью fcntl().  POSIX, таблица 6-3. */
 00930	#define F_RDLCK            1    /* блокировка без монополизации или для чтения */
 00931	#define F_WRLCK            2    /* блокировка с монополизацией или для записи */
 00932	#define F_UNLCK            3    /* снятие блокировки */
 00933	
 00934	/* Значения Oflag для open().  POSIX, таблица 6-4. */
 00935	#define O_CREAT        00100    /* создать файл, если он не существует */
 00936	#define O_EXCL         00200    /* флаг эксклюзивного использования */
 00937	#define O_NOCTTY       00400    /* не назначать управляющий терминал */
 00938	#define O_TRUNC        01000    /* флаг отсечения */
 00939	
 00940	/* Флаги состояния файла для open() и fcntl().  POSIX, таблица 6-5. */
 00941	#define O_APPEND       02000    /* установка режима добавления */
 00942	#define O_NONBLOCK     04000    /* отсутствие задержки */
 00943	
 00944	/* Режимы доступа к файлам для open() и fcntl().  POSIX, таблица 6-6. */
 00945	#define O_RDONLY           0    /* open(name, O_RDONLY) открывает только для чтения */
 00946	#define O_WRONLY           1    /* open(name, O_WRONLY) открывает только для записи */
 00947	#define O_RDWR             2    /* open(name, O_RDWR) открывает для чтения и записи */
 00948	
 00949	/* Маска для режимов файлового доступа.  POSIX, таблица 6-7. */
 00950	#define O_ACCMODE         03    /* маска для режимов файлового доступа */
 00951	
 00952	/* Структура для блокирования.  POSIX, таблица 6-8. */
 00953	struct flock {
 00954	  short l_type;                 /* тип:  F_RDLCK, F_WRLCK или F_UNLCK */
 00955	  short l_whence;               /* флаг начала смещения */
 00956	  off_t l_start;                /* относительное смещение в байтах */
 00957	  off_t l_len;                  /* размер; если 0, то до конца файла */
 00958	  pid_t l_pid;                  /* идентификатор процесса владельца блокировки */
 00959	};
 00960	
 00961	/* Прототипы функций. */
 00962	_PROTOTYPE( int creat, (const char *_path, _mnx_Mode_t _mode)           );
 00963	_PROTOTYPE( int fcntl, (int _filedes, int _cmd, ...)                    );
 00964	_PROTOTYPE( int open,  (const char *_path, int _oflag, ...)             );
 00965	
 00966	#endif /* _FCNTL_H */




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/termios.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 01000	/* Заголовочный файл <termios.h> используется для управления режимами терминала. */
 01001	
 01002	#ifndef _TERMIOS_H
 01003	#define _TERMIOS_H
 01004	
 01005	typedef unsigned short tcflag_t;
 01006	typedef unsigned char cc_t;
 01007	typedef unsigned int speed_t;
 01008	
 01009	#define NCCS               20   /* размер массива cc_c, дополнительное место
 01010	                                 * оставлено под расширения. */
 01011	
 01012	/* Главная структура управления терминалом. POSIX, таблица 7-1. */
 01013	struct termios {
 01014	  tcflag_t c_iflag;             /* режимы ввода */
 01015	  tcflag_t c_oflag;             /* режимы вывода */
 01016	  tcflag_t c_cflag;             /* режимы управления */
 01017	  tcflag_t c_lflag;             /* локальные режимы */
 01018	  speed_t  c_ispeed;            /* скорость ввода */
 01019	  speed_t  c_ospeed;            /* скорость вывода */
 01020	  cc_t c_cc[NCCS];              /* символы управления */
 01021	};
 01022	
 01023	/* Значения для битового массива termios c_iflag.  POSIX, таблица 7-2. */
 01024	#define BRKINT          0x0001  /* прерывание или разрыв сигнала */
 01025	#define ICRNL           0x0002  /* преобразование CR в NL при вводе*/
 01026	#define IGNBRK          0x0004  /* игнорировать break */
 01027	#define IGNCR           0x0008  /* игнорировать CR */
 01028	#define IGNPAR          0x0010  /* игнорировать символы с ошибками четности */
 01029	#define INLCR           0x0020  /* преобразование NL в CR при вводе */
 01030	#define INPCK           0x0040  /* включить проверку четности ввода */
 01031	#define ISTRIP          0x0080  /* маскирование 8-го бита */
 01032	#define IXOFF           0x0100  /* начать/прекрать контроль ввода */
 01033	#define IXON            0x0200  /* начать/прекрать контроль вывода */
 01034	#define PARMRK          0x0400  /* отмечать ошибки четности во входной очереди */
 01035	
 01036	/* Значения для битового массива termios c_oflag.  POSIX Sec. 7.1.2.3. */
 01037	#define OPOST           0x0001  /* выполнять обработку вывода */
 01038	
 01039	/* Значения для битового массива termios c_cflag.  POSIX, таблица 7-3. */
 01040	#define CLOCAL          0x0001  /* игнорировать строки состояния модема */
 01041	#define CREAD           0x0002  /* включить приемник */
 01042	#define CSIZE           0x000C  /* число битов в символе */
 01043	#define         CS5     0x0000  /* если CSIZE = CS5, символы 5-разрядные */
 01044	#define         CS6     0x0004  /* если CSIZE = CS6, символы 6-разрядные */
 01045	#define         CS7     0x0008  /* если CSIZE = CS7, символы 7-разрядные */
 01046	#define         CS8     0x000C  /* если CSIZE = CS8, символы 8-разрядные */
 01047	#define CSTOPB          0x0010  /* если задан, послать 2 стоп-бита, иначе 1 */
 01048	#define HUPCL           0x0020  /* зависание при последнем закрытии */
 01049	#define PARENB          0x0040  /* включить контроль четности для вывода */
 01050	#define PARODD          0x0080  /* если задан, использовать проверку на нечетность, иначе на четность  */
 01051	
 01052	/* Значения для битового массива termios c_lflag.  POSIX, таблица 7-4. */
 01053	#define ECHO            0x0001  /* включить эхо вводимых символов */
 01054	#define ECHOE           0x0002  /* эхо ERASE как символа забоя*/
 01055	#define ECHOK           0x0004  /* эхо KILL */
 01056	#define ECHONL          0x0008  /* эхо NL */
 01057	#define ICANON          0x0010  /* канонический ввод (команды erase и kill разрешены) */
 01058	#define IEXTEN          0x0020  /* разрешить расширенные функции */
 01059	#define ISIG            0x0040  /* разрешить сигналы */
 01060	#define NOFLSH          0x0080  /* отключить сброс после прерывания и выхода */
 01061	#define TOSTOP          0x0100  /* послать SIGTTOU (контроль задания, не реализовано) */
 01062	
 01063	/* Индексы массива c_cc.  Значения по умолчанию указаны в круглых скобках. POSIX, таблица 7-5. */
 01064	#define VEOF                 0  /* cc_c[VEOF] = EOF (^D) */
 01065	#define VEOL                 1  /* cc_c[VEOL] = EOL (undef) */
 01066	#define VERASE               2  /* cc_c[VERASE] = ERASE (^H) */
 01067	#define VINTR                3  /* cc_c[VINTR] = INTR (DEL) */
 01068	#define VKILL                4  /* cc_c[VKILL] = KILL (^U) */
 01069	#define VMIN                 5  /* cc_c[VMIN] = минимальное значение для таймера */
 01070	#define VQUIT                6  /* cc_c[VQUIT] = QUIT (^\) */
 01071	#define VTIME                7  /* cc_c[VTIME] = значение TIME для таймера */
 01072	#define VSUSP                8  /* cc_c[VSUSP] = SUSP (^Z, игнорируется) */
 01073	#define VSTART               9  /* cc_c[VSTART] = START (^S) */
 01074	#define VSTOP               10  /* cc_c[VSTOP] = STOP (^Q) */
 01075	
 01076	#define _POSIX_VDISABLE   (cc_t)0xFF    /* Этот символ невозможно сгенерировать при 
 01077	                                         * помощи "обычной" клавиатуры.
 01078	                                         * Тем не менее, его генерируют некоторые
 01079	                                         * клавиатуры, зависимые от языка. Похоже, 
 01080	                                         * используются все 256 символов, и cc_t следует 
 01081	                                         * иметь тип short...
 01082	                                         */
 01083	
 01084	/* Значения параметров двоичной передачи.  POSIX, таблица 7-6. */
 01085	#define B0              0x0000  /* зависание линии */
 01086	#define B50             0x1000  /* 50 бод */
 01087	#define B75             0x2000  /* 75 бод */
 01088	#define B110            0x3000  /* 110 бод */
 01089	#define B134            0x4000  /* 134.5 бод */
 01090	#define B150            0x5000  /* 150 бод */
 01091	#define B200            0x6000  /* 200 бод */
 01092	#define B300            0x7000  /* 300 бод */
 01093	#define B600            0x8000  /* 600 бод */
 01094	#define B1200           0x9000  /* 1200 бод */
 01095	#define B1800           0xA000  /* 1800 бод */
 01096	#define B2400           0xB000  /* 2400 бод */
 01097	#define B4800           0xC000  /* 4800 бод */
 01098	#define B9600           0xD000  /* 9600 бод */
 01099	#define B19200          0xE000  /* 19200 бод */
 01100	#define B38400          0xF000  /* 38400 бод */
 01101	
 01102	/* Дополнительные действия для tcsetattr().  POSIX Sec. 7.2.1.2. */
 01103	#define TCSANOW            1    /* изменения имеют немедленное действие */
 01104	#define TCSADRAIN          2    /* изменения вступают в силу после завершения вывода*/
 01105	#define TCSAFLUSH          3    /* ожидание окончания вывода и сброса ввода */
 01106	
 01107	/* Значения Queue_selector для tcflush().  POSIX Sec. 7.2.2.2. */
 01108	#define TCIFLUSH           1    /* сбросить накопленные входные данные */
 01109	#define TCOFLUSH           2    /* сбросить накопленные выходные данные */
 01110	#define TCIOFLUSH          3    /* сбросить накопленные входные и выходные данные */
 01111	
 01112	/* Значения Action для tcflow().  POSIX Sec. 7.2.2.2. */
 01113	#define TCOOFF             1    /* приостановить вывод */
 01114	#define TCOON              2    /* продолжить приостановленный вывод */
 01115	#define TCIOFF             3    /* передать символ STOP */
 01116	#define TCION              4    /* передать символ START */
 01117	
 01118	/* Прототипы функций. */
 01119	#ifndef _ANSI_H
 01120	#include <ansi.h>
 01121	#endif
 01122	
 01123	_PROTOTYPE( int tcsendbreak, (int _fildes, int _duration)                    );
 01124	_PROTOTYPE( int tcdrain, (int _filedes)                                      );
 01125	_PROTOTYPE( int tcflush, (int _filedes, int _queue_selector)                 );
 01126	_PROTOTYPE( int tcflow, (int _filedes, int _action)                          );
 01127	_PROTOTYPE( speed_t cfgetispeed, (const struct termios *_termios_p)          );
 01128	_PROTOTYPE( speed_t cfgetospeed, (const struct termios *_termios_p)          );
 01129	_PROTOTYPE( int cfsetispeed, (struct termios *_termios_p, speed_t _speed)    );
 01130	_PROTOTYPE( int cfsetospeed, (struct termios *_termios_p, speed_t _speed)    );
 01131	_PROTOTYPE( int tcgetattr, (int _filedes, struct termios *_termios_p)        );
 01132	_PROTOTYPE( int tcsetattr, \
 01133	        (int _filedes, int _opt_actions, const struct termios *_termios_p)   );
 01134	
 01135	#define cfgetispeed(termios_p)          ((termios_p)->c_ispeed)
 01136	#define cfgetospeed(termios_p)          ((termios_p)->c_ospeed)
 01137	#define cfsetispeed(termios_p, speed)   ((termios_p)->c_ispeed = (speed), 0)
 01138	#define cfsetospeed(termios_p, speed)   ((termios_p)->c_ospeed = (speed), 0)
 01139	
 01140	#ifdef _MINIX
 01141	/* Локальные расширения стандарта POSIX в ОС Minix. Программы в стандарте POSIX
 01142	 * не имеют к ним доступа, поэтому эти расширения определяются только при компиляции
 01143	 * Minix-программы.
 01144	 */
 01145	
 01146	/* Расширения битового массива termios c_iflag */
 01147	#define IXANY           0x0800  /* разрешить любой клавише продолжить вывод */
 01148	
 01149	/* Расширения битового массива termios c_oflag. Они активны, лишь если включен
 01150	 * OPOST. */
 01151	#define ONLCR           0x0002  /* Замена NL на CR-NL при выводе */
 01152	#define XTABS           0x0004  /* Замена табуляций пробелами */
 01153	#define ONOEOT          0x0008  /* Исключение EOT (^D) при выводе) */
 01154	
 01155	/* Расширения битового массива termios c_lflag.  */
 01156	#define LFLUSHO         0x0200  /* Сброс вывода. */
 01157	
 01158	/* Расширения массива c_cc. */
 01159	#define VREPRINT          11    /* cc_c[VREPRINT] (^R) */
 01160	#define VLNEXT            12    /* cc_c[VLNEXT] (^V) */
 01161	#define VDISCARD          13    /* cc_c[VDISCARD] (^O) */
 01162	
 01163	/* Расширения параметров двоичной передачи. */
 01164	#define B57600          0x0100  /* 57600 бод */
 01165	#define B115200         0x0200  /* 115200 бод */
 01166	
 01167	/* Значения, используемые по умолчанию ядром и 'stty sane' */
 01168	
 01169	#define TCTRL_DEF       (CREAD | CS8 | HUPCL)
 01170	#define TINPUT_DEF      (BRKINT | ICRNL | IXON | IXANY)
 01171	#define TOUTPUT_DEF     (OPOST | ONLCR)
 01172	#define TLOCAL_DEF      (ISIG | IEXTEN | ICANON | ECHO | ECHOE)
 01173	#define TSPEED_DEF      B9600
 01174	
 01175	#define TEOF_DEF        '\4'    /* ^D */
 01176	#define TEOL_DEF        _POSIX_VDISABLE
 01177	#define TERASE_DEF      '\10'   /* ^H */
 01178	#define TINTR_DEF       '\3'    /* ^C */
 01179	#define TKILL_DEF       '\25'   /* ^U */
 01180	#define TMIN_DEF        1
 01181	#define TQUIT_DEF       '\34'   /* ^\ */
 01182	#define TSTART_DEF      '\21'   /* ^Q */
 01183	#define TSTOP_DEF       '\23'   /* ^S */
 01184	#define TSUSP_DEF       '\32'   /* ^Z */
 01185	#define TTIME_DEF       0
 01186	#define TREPRINT_DEF    '\22'   /* ^R */
 01187	#define TLNEXT_DEF      '\26'   /* ^V */
 01188	#define TDISCARD_DEF    '\17'   /* ^O */
 01189	
 01190	/* Размер окна. Эта информация хранится в драйвере терминала, но не используется.
 01191	 * Она может быть использована приложениями, осуществляющими вывод на экран в оконной среде. 
 01192	 * Считать и установить эту информацию можно с помощью 
 01193	 * TIOCGWINSZ и TIOCSWINSZ.
 01194	 */
 01195	
 01196	struct winsize
 01197	{
 01198	        unsigned short  ws_row;         /* строки в символах */
 01199	        unsigned short  ws_col;         /* столбцы в символах */
 01200	        unsigned short  ws_xpixel;      /* горизонтальный размер в пикселах */
 01201	        unsigned short  ws_ypixel;      /* вертикальный размер в пикселах */
 01202	};
 01203	#endif /* _MINIX */
 01204	
 01205	#endif /* _TERMIOS_H */
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/timers.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 01300	/* Эта библиотека предоставляет общие функции управления сторожевым таймером. Функции
 01301	 * обрабатывают очередь таймера, передаваемую вызывающим процессом. Сортировка возможна,
 01302	 * только если таймеры используют абсолютное время. Функции библиотеки
 01303	 *
 01304	 *    tmrs_settimer:      установка нового сторожевого таймера в очередь
 01305	 *    tmrs_clrtimer:      удаление таймера из очереди
 01306	 *    tmrs_exptimers:     поиск истекших таймеров и запуск сторожевых функций
 01307	 *
 01308	 * Автор: 
 01309	 *    Jorrit N. Herder <jnherder@cs.vu.nl>
 01310	 *    Упрощенный вариант из tmr_settimer и tmr_clrtimer (файл src/kernel/clock.c). 
 01311	 *    Последняя модификация:  30 сентября 2004.
 01312	 */
 01313	
 01314	#ifndef _TIMERS_H
 01315	#define _TIMERS_H
 01316	
 01317	#include <limits.h>
 01318	#include <sys/types.h>
 01319	
 01320	struct timer;
 01321	typedef void (*tmr_func_t)(struct timer *tp);
 01322	typedef union { int ta_int; long ta_long; void *ta_ptr; } tmr_arg_t;
 01323	
 01324	/* Переменная timer_t должна быть объявлена для каждого отдельного таймера.
 01325	 * Сторожевая функция таймера и время истечения автоматически устанавливаются
 01326	 * библиотечной функцией tmrs_settimer, но это не касается ее аргумента.
 01327	 */
 01328	typedef struct timer
 01329	{
 01330	  struct timer  *tmr_next;      /* следующий таймер в цепочке */
 01331	  clock_t       tmr_exp_time;   /* время истечения */
 01332	  tmr_func_t    tmr_func;       /* функция, вызываемая при завершении таймера */
 01333	  tmr_arg_t     tmr_arg;        /* случайный аргумент */
 01334	} timer_t;
 01335	
 01336	/* Используется, когда таймер не активен. */
 01337	#define TMR_NEVER    ((clock_t) -1 < 0) ? ((clock_t) LONG_MAX) :  ((clock_t) -1)
 01338	#undef TMR_NEVER
 01339	#define TMR_NEVER       ((clock_t) LONG_MAX)
 01340	
 01341	/* Эти определения могут использоваться для установки или считывания данных переменной таймера. */ 
 01342	#define tmr_arg(tp) (&(tp)->tmr_arg)
 01343	#define tmr_exp_time(tp) (&(tp)->tmr_exp_time)
 01344	
 01345	/* Таймеры должны инициализоваться один раз до использования. Будьте аккуратны: не
 01346	 * инициализируйте заново таймеры, находящиеся в очереди, поскольку это приведет к
 01347	 * разрыву цепочки.
 01348	 */
 01349	#define tmr_inittimer(tp) (void)((tp)->tmr_exp_time = TMR_NEVER, \
 01350	        (tp)->tmr_next = NULL)
 01351	
 01352	/* Следующие общие функции управления можно использовать для работы со списками
 01353	 * таймеров. Добавление таймера в очередь автоматически предусматривает его
 01354   * удалении.
 01355	 */
 01356	_PROTOTYPE( clock_t tmrs_clrtimer, (timer_t **tmrs, timer_t *tp, clock_t *new_head)             );
 01357	_PROTOTYPE( void tmrs_exptimers, (timer_t **tmrs, clock_t now, clock_t *new_head)               );
 01358	_PROTOTYPE( clock_t tmrs_settimer, (timer_t **tmrs, timer_t *tp, 
 01359	        clock_t exp_time, tmr_func_t watchdog, clock_t *new_head)                               );
 01360	
 01361	#endif /* _TIMERS_H */
 01362	

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/sys/types.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 01400	/* Заголовочный файл <sys/types.h> содержит важные определения типов данных.
 01401	 * Использование этих определений вместо базовых типов данных считается 
 01402	 * хорошей практикой программирования. По соглашению все имена типов имеют
 01403	 * окончание _t.
 01404	 */
 01405	
 01406	#ifndef _TYPES_H
 01407	#define _TYPES_H
 01408	
 01409	#ifndef _ANSI_H
 01410	#include <ansi.h>
 01411	#endif
 01412	
 01413	/* Тип size_t охватывает все результаты оператора sizeof. Изначально кажется очевидным,
 01414	 * что этот тип должен совпадать с unsigned int, однако это не всегда так. Например,
 01415	 * MINIX-ST (68000) имеет 32-разрядные указатели, а разрядность целых чисел составляет 16
 01416	 * бит. Если запрошен размер структуры и массива величиной в 70 Кбайт, результат 
 01417	 * должен быть 17-разрядным, поэтому size_t следует описать как тип long. Тип ssize_t
 01418	 * представляет собой знаковую версию size_t.
 01419	 */
 01420	#ifndef _SIZE_T
 01421	#define _SIZE_T
 01422	typedef unsigned int size_t;
 01423	#endif
 01424	
 01425	#ifndef _SSIZE_T
 01426	#define _SSIZE_T
 01427	typedef int ssize_t;
 01428	#endif
 01429	
 01430	#ifndef _TIME_T
 01431	#define _TIME_T
 01432	typedef long time_t;               /* время в секундах с 1 января 1970 г. по Гринвичу */
 01433	#endif
 01434	
 01435	#ifndef _CLOCK_T
 01436	#define _CLOCK_T
 01437	typedef long clock_t;              /* единица учета системы */
 01438	#endif
 01439	
 01440	#ifndef _SIGSET_T
 01441	#define _SIGSET_T
 01442	typedef unsigned long sigset_t;
 01443	#endif
 01444	
 01445	/* Спецификации Open Group Base Specifications Issue 6 (не завершено) */
 01446	typedef long useconds_t;        /* Время в микросекундах */
 01447	
 01448	/* Типы, используемые в структурах данных дисков, индексных узлов и т. д. */
 01449	typedef short          dev_t;      /* пара главного и вспомогательного номеров устройств */
 01450	typedef char           gid_t;      /* идентификатор группы */
 01451	typedef unsigned long  ino_t;      /* номер индексного узла (файловая система V3) */
 01452	typedef unsigned short mode_t;     /* тип файла и биты разрешений */
 01453	typedef short        nlink_t;      /* число связей файла */
 01454	typedef unsigned long  off_t;      /* смещение внутри файла */
 01455	typedef int            pid_t;      /* идентификатор процесса (должно быть знаковым) */
 01456	typedef short          uid_t;      /* идентификатор пользователя */
 01457	typedef unsigned long zone_t;      /* номер зоны */
 01458	typedef unsigned long block_t;     /* номер блока */
 01459	typedef unsigned long  bit_t;      /* номер бита в битовой карте */
 01460	typedef unsigned short zone1_t;    /* номер зоны для файловых систем V1 */
 01461	typedef unsigned short bitchunk_t; /* набор битов в битовой карте */
 01462	
 01463	typedef unsigned char   u8_t;      /* 8-разрядный тип */
 01464	typedef unsigned short u16_t;      /* 16-разрядный тип */
 01465	typedef unsigned long  u32_t;      /* 32-разрядный тип */
 01466	
 01467	typedef char            i8_t;      /* 8-разрядный знаковый тип */
 01468	typedef short          i16_t;      /* 16-разрядный знаковый тип */
 01469	typedef long           i32_t;      /* 32-разрядный знаковый тип */
 01470	
 01471	typedef struct { u32_t _[2]; } u64_t;
 01472	
 01473	/* Следующие типы необходимы потому, что MINIX использует определения функций в стиле
 01474	 * Кернигана и Ричи (для обеспечения максимальной переносимости). Когда тип, основанный
 01475	 * на short, например, dev_t, передается в функцию, определенную согласно Кернигану
 01476	 * и Ричи, компилятор автоматически преобразует его в int. Прототип должен содержать 
 01477	 * в качестве параметра int, а не short, поскольку int ожидается в устаревшем определении 
 01478	 * функции. Использование в прототипе типа dev_t будет некорректным. В прототипах 
 01479	 * достаточно указывать тип int вместо dev_t, однако запись Dev_t будет более
 01480	 * понятной.
 01481	 */
 01482	typedef int            Dev_t;
 01483	typedef int       _mnx_Gid_t;
 01484	typedef int          Nlink_t;
 01485	typedef int       _mnx_Uid_t;
 01486	typedef int             U8_t;
 01487	typedef unsigned long  U32_t;
 01488	typedef int             I8_t;
 01489	typedef int            I16_t;
 01490	typedef long           I32_t;
 01491	
 01492	/* ANSI C вносит значительную путаницу в запись продвижения беззнаковых типов.
 01493	 * Когда sizeof(short) == sizeof(int), продвижения не происходит, и тип остается
 01494	 * беззнаковым. При использовании компиляторов, отличных от ANSI, потери беззнаковости,
 01495	 * как правило, не происходит, прототипы обычно не используются и продвигаемый тип не
 01496	 * имеет значения. Типы, подобные Ino_t, являются попыткой одновременно использовать
 01497	 * непродвигаемый тип int и сделать код информативным для читателя.
 01498	 */
 01499	
 01500	typedef unsigned long  Ino_t;
 01501	
 01502	#if _EM_WSIZE == 2
 01503	/*typedef unsigned int      Ino_t; теперь тип Ino_t 32-разрядный */
 01504	typedef unsigned int    Zone1_t;
 01505	typedef unsigned int Bitchunk_t;
 01506	typedef unsigned int      U16_t;
 01507	typedef unsigned int  _mnx_Mode_t;
 01508	
 01509	#else /* _EM_WSIZE == 4, либо константа _EM_WSIZE не определена */
 01510	/*typedef int             Ino_t; теперь тип Ino_t 32-разрядный */
 01511	typedef int             Zone1_t;
 01512	typedef int          Bitchunk_t;
 01513	typedef int               U16_t;
 01514	typedef int         _mnx_Mode_t;
 01515	
 01516	#endif /* _EM_WSIZE == 2, etc */
 01517	 
 01518	/* Тип обработчика сигналов, например, SIG_IGN */
 01519	typedef void _PROTOTYPE( (*sighandler_t), (int) );
 01520	
 01521	/* Для совместимости с другими системами */
 01522	typedef unsigned char   u_char;
 01523	typedef unsigned short  u_short;
 01524	typedef unsigned int    u_int;
 01525	typedef unsigned long   u_long;
 01526	typedef char            *caddr_t;
 01527	
 01528	#endif /* _TYPES_H */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/sys/sigcontext.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 01600	#ifndef _SIGCONTEXT_H
 01601	#define _SIGCONTEXT_H
 01602	
 01603	/* Структура sigcontext используется системным вызовом sigreturn(2).
 01604	 * sigreturn() редко вызывается пользовательскими программами, однако применяется
 01605	 * механизмом обработки сигналов.
 01606	 */
 01607	
 01608	#ifndef _ANSI_H
 01609	#include <ansi.h>
 01610	#endif
 01611	
 01612	#ifndef _MINIX_SYS_CONFIG_H
 01613	#include <minix/sys_config.h>
 01614	#endif
 01615	
 01616	#if !defined(_MINIX_CHIP)
 01617	#include "error, configuration is not known"
 01618	#endif
 01619	
01620  /* Следующая структура должна соответствовать структуре stackframe_s, которую использует
 01621	 * код ядра, осуществляющий переключение контекста. Регистры вещественных чисел следует
 01622	 * добавлять в отдельную структуру.
 01623	 */
 01624	struct sigregs {  
 01625	  short sr_gs;
 01626	  short sr_fs;
 01627	  short sr_es;
 01628	  short sr_ds;
 01629	  int sr_di;
 01630	  int sr_si;
 01631	  int sr_bp;
 01632	  int sr_st;                    /* вершина стека – используется ядром */
 01633	  int sr_bx;
 01634	  int sr_dx;
 01635	  int sr_cx;
 01636	  int sr_retreg;
 01637	  int sr_retadr;                /* адрес возврата вызывающего процесса -- используется
 01638	                                 * ядром */
 01639	  int sr_pc;
 01640	  int sr_cs;
 01641	  int sr_psw;
 01642	  int sr_sp;
 01643	  int sr_ss;
 01644	};
 01645	
 01646	struct sigframe {               /* кадр стека, созданный для процесса-приемника сигнала */
 01647	  _PROTOTYPE( void (*sf_retadr), (void) );
 01648	  int sf_signo;
 01649	  int sf_code;
 01650	  struct sigcontext *sf_scp;
 01651	  int sf_fp;
 01652	  _PROTOTYPE( void (*sf_retadr2), (void) );
 01653	  struct sigcontext *sf_scpcopy;
 01654	};
 01655	
 01656	struct sigcontext {
 01657	  int sc_flags;                 /* состояние sigstack для восстановления */
 01658	  long sc_mask;                 /* маска сигнала для восстановления */
 01659	  struct sigregs sc_regs;       /* набор регистров для восстановления */
 01660	};
 01661	
 01662	#define sc_gs sc_regs.sr_gs
 01663	#define sc_fs sc_regs.sr_fs
 01664	#define sc_es sc_regs.sr_es
 01665	#define sc_ds sc_regs.sr_ds
 01666	#define sc_di sc_regs.sr_di
 01667	#define sc_si sc_regs.sr_si 
 01668	#define sc_fp sc_regs.sr_bp
 01669	#define sc_st sc_regs.sr_st             /* вершина стека – используется ядром */
 01670	#define sc_bx sc_regs.sr_bx
 01671	#define sc_dx sc_regs.sr_dx
 01672	#define sc_cx sc_regs.sr_cx
 01673	#define sc_retreg sc_regs.sr_retreg
 01674	#define sc_retadr sc_regs.sr_retadr     /* адрес возврата вызывающего процесса -- используется
 01675	                                        ядром */
 01676	#define sc_pc sc_regs.sr_pc
 01677	#define sc_cs sc_regs.sr_cs
 01678	#define sc_psw sc_regs.sr_psw
 01679	#define sc_sp sc_regs.sr_sp
 01680	#define sc_ss sc_regs.sr_ss
 01681	
 01682	/* Значения для sc_flags. Они должны согласовываться с файлом <minix/jmp_buf.h>. */
 01683	#define SC_SIGCONTEXT   2       /* не ноль, если включен контекст сигнала */
 01684	#define SC_NOREGLOCALS  4       /* не ноль, если регистры не нужно сохранять
 01685	                                        и восстанавливать */
 01686	
 01687	_PROTOTYPE( int sigreturn, (struct sigcontext *_scp)                    );
 01688	
 01689	#endif /* _SIGCONTEXT_H */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/sys/stat.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 01700	/* Заголовочный файл <sys/stat.h> определяет структуру, используемую в функциях stat()
 01701	 * и fstat. Информация, хранимая в структуре, извлекается из индексного узла некоторого файла.
 01702	 * Данные вызовы являются единственно одобренным способом получения данных индексных узлов.
 01703	 */
 01704	
 01705	#ifndef _STAT_H
 01706	#define _STAT_H
 01707	
 01708	#ifndef _TYPES_H
 01709	#include <sys/types.h>
 01710	#endif
 01711	
 01712	struct stat {
 01713	  dev_t st_dev;                 /* главный/вспомогательный номер устройства */
 01714	  ino_t st_ino;                 /* номер индексного узла */
 01715	  mode_t st_mode;               /* режим файла, биты защиты и др. */
 01716	  short int st_nlink;           /* число связей; ВРЕМЕННЫЙ ТРЮК: должен быть тип nlink_t*/
 01717	  uid_t st_uid;                 /* uid владельца файла */
 01718	  short int st_gid;             /* gid; ВРЕМЕННЫЙ ТРЮК: должен быть тип gid_t */
 01719	  dev_t st_rdev;
 01720	  off_t st_size;                /* размер файла */
 01721	  time_t st_atime;              /* время последнего доступа */
 01722	  time_t st_mtime;              /* время последней модификации данных */
 01723	  time_t st_ctime;              /* время последнего изменения состояния */
 01724	};
 01725	
 01726	/* Традиционные определения маски для st_mode. */
 01727	/* Не слишком изящные преобразования типов в некоторых определениях необходимы во избежание
 01728	 * побочных знаковых расширений при разрядности типа int в 32 бита (например, S_IFREG != (mode_t) S_IFREG)
 01729	 */
 01730	#define S_IFMT  ((mode_t) 0170000)      /* тип файла */
 01731	#define S_IFLNK ((mode_t) 0120000)      /* символическая связь, не реализована */
 01732	#define S_IFREG ((mode_t) 0100000)      /* обычный файл */
 01733	#define S_IFBLK 0060000         /* блочное специальное устройство */
 01734	#define S_IFDIR 0040000         /* каталог */
 01735	#define S_IFCHR 0020000         /* символьное специальное устройство */
 01736	#define S_IFIFO 0010000         /* FIFO */
 01737	#define S_ISUID 0004000         /* установить идентификатор пользователя при исполнении */
 01738	#define S_ISGID 0002000         /* установить идентификатор группы при исполнении */
 01739	                                /* следующий зарезервирован для будущего использования */
 01740	#define S_ISVTX   01000         /* сохранить замененный текст после использования */
 01741	
 01742	/* POSIX masks for st_mode. */
 01743	#define S_IRWXU   00700         /* владелец:   rwx------ */
 01744	#define S_IRUSR   00400         /* владелец:   r-------- */
 01745	#define S_IWUSR   00200         /* владелец:   -w------- */
 01746	#define S_IXUSR   00100         /* владелец:   --x------ */
 01747	
 01748	#define S_IRWXG   00070         /* группа:   ---rwx--- */
 01749	#define S_IRGRP   00040         /* группа:   ---r----- */
 01750	#define S_IWGRP   00020         /* группа:   ----w---- */
 01751	#define S_IXGRP   00010         /* группа:   -----x--- */
 01752	
 01753	#define S_IRWXO   00007         /* прочие:  ------rwx */
 01754	#define S_IROTH   00004         /* прочие:  ------r-- */ 
 01755	#define S_IWOTH   00002         /* прочие:  -------w- */
 01756	#define S_IXOTH   00001         /* прочие:  --------x */
 01757	
 01758	/* Следующие макросы проверяют st_mode (POSIX Sec. 5.6.1.1). */
 01759	#define S_ISREG(m)      (((m) & S_IFMT) == S_IFREG)     /* обычный файл */
 01760	#define S_ISDIR(m)      (((m) & S_IFMT) == S_IFDIR)     /* каталог */
 01761	#define S_ISCHR(m)      (((m) & S_IFMT) == S_IFCHR)     /* спец. симв. */
 01762	#define S_ISBLK(m)      (((m) & S_IFMT) == S_IFBLK)     /* спец. блоч. */
 01763	#define S_ISFIFO(m)     (((m) & S_IFMT) == S_IFIFO)     /* канал/FIFO */
 01764	#define S_ISLNK(m)      (((m) & S_IFMT) == S_IFLNK)     /* символическая связь */
 01765	
 01766	/* Прототипы функций. */
 01767	_PROTOTYPE( int chmod, (const char *_path, _mnx_Mode_t _mode)           );
 01768	_PROTOTYPE( int fstat, (int _fildes, struct stat *_buf)                 );
 01769	_PROTOTYPE( int mkdir, (const char *_path, _mnx_Mode_t _mode)           );
 01770	_PROTOTYPE( int mkfifo, (const char *_path, _mnx_Mode_t _mode)          );
 01771	_PROTOTYPE( int stat, (const char *_path, struct stat *_buf)            );
 01772	_PROTOTYPE( mode_t umask, (_mnx_Mode_t _cmask)                          );
 01773	
 01774	/* Open Group Base Specifications Issue 6 (не завершено) */
 01775	_PROTOTYPE( int lstat, (const char *_path, struct stat *_buf)           );
 01776	
 01777	#endif /* _STAT_H */



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/sys/dir.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 01800	/* Заголовочный файл <dir.h> описывает структуру каталога. */
 01801	
 01802	#ifndef _DIR_H
 01803	#define _DIR_H
 01804	
 01805	#include <sys/types.h>
 01806	
 01807	#define DIRBLKSIZ       512     /* размер блока каталога */
 01808	
 01809	#ifndef DIRSIZ
 01810	#define DIRSIZ  60
 01811	#endif
 01812	
 01813	struct direct {
 01814	  ino_t d_ino;
 01815	  char d_name[DIRSIZ];
 01816	};
 01817	
 01818	#endif /* _DIR_H */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/sys/wait.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 01900	/* Заголовочный файл <sys/wait.h> содержит макросы, связанные с функцией wait().
 01901	 * Значение, возвращаемое wait() и waitpid() зависит от способа завершения процесса: 
 01902	 * вызовом exit(), сигналом или остановкой из-за контроля задания, как показано
 01903	 * далее: 
 01904	 *
 01905	 *                               Старший байт Младший байт
 01906	 *                              +-------------------------+
 01907	 *      exit(состояние)         |  состояние |    0       |
 01908	 *                              +-------------------------+
 01909	 *      завершение по сигналу   |    0       |  сигнал    |
 01910	 *                              +-------------------------+
 01911	 * остановка (контроль заданий) |  сигнал    |   0177     |
 01912	 *                              +-------------------------+
 01913	 */
 01914	
 01915	#ifndef _WAIT_H
 01916	#define _WAIT_H
 01917	
 01918	#ifndef _TYPES_H
 01919	#include <sys/types.h>
 01920	#endif
 01921	
 01922	#define _LOW(v)         ( (v) & 0377)
 01923	#define _HIGH(v)        ( ((v) >> 8) & 0377)
 01924	
 01925	#define WNOHANG         1       /* не ждать завершение потомка */
 01926	#define WUNTRACED       2       /* для контроля заданий; не реализовано */
 01927	
 01928	#define WIFEXITED(s)    (_LOW(s) == 0)                      /* нормальное завершение */
 01929	#define WEXITSTATUS(s)  (_HIGH(s))                          /* состояние завершения */
 01930	#define WTERMSIG(s)     (_LOW(s) & 0177)                    /* значение сигнала */
 01931	#define WIFSIGNALED(s)  (((unsigned int)(s)-1 & 0xFFFF) < 0xFF) /* по сигналу */
 01932	#define WIFSTOPPED(s)   (_LOW(s) == 0177)                   /* останов */
 01933	#define WSTOPSIG(s)     (_HIGH(s) & 0377)                   /* сигнал останова*/
 01934	
 01935	/* Прототипы функций. */
 01936	_PROTOTYPE( pid_t wait, (int *_stat_loc)                                   );
 01937	_PROTOTYPE( pid_t waitpid, (pid_t _pid, int *_stat_loc, int _options)      );
 01938	
 01939	#endif /* _WAIT_H */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/sys/ioctl.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 02000	/*      sys/ioctl.h – Все коды команды ioctl().                 Автор:  Kees J. Bot
 02001	 *                                                              23 ноября 2002
 02002	 *
 02003	 * Этот заголовочный файл включает все прочие заголовочные файлы кода команды ioctl.
 02004	 */
 02005	
 02006	#ifndef _S_IOCTL_H
 02007	#define _S_IOCTL_H
 02008	
 02009	/* Драйвер, использующий ioctl, объявляет символ для своей последовательности команд.
 02010	 * Пример:  #define TCGETS  _IOR('T',  8, struct termios)
 02011	 * Это ioctl терминала с символом 'T'. Символ(ы), используемые в каждом
 02012	 * заголовочном файле, перечислены в следующем комментарии.
 02013	 */
 02014	
 02015	#include <sys/ioc_tty.h>        /* 'T' 't' 'k'          */
 02016	#include <sys/ioc_disk.h>       /* 'd'                  */
 02017	#include <sys/ioc_memory.h>     /* 'm'                  */
 02018	#include <sys/ioc_cmos.h>       /* 'c'                  */
 02019	
 02020	#endif /* _S_IOCTL_H */





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/sys/ioc_disk.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 02100	/*      sys/ioc_disk.h – Коды команды ioctl() для диска.       Автор:  Kees J. Bot
 02101	 *                                                             23 ноября 2002
 02102	 *
 02103	 */
 02104	
 02105	#ifndef _S_I_DISK_H
 02106	#define _S_I_DISK_H
 02107	
 02108	#include <minix/ioctl.h>
 02109	
 02110	#define DIOCSETP        _IOW('d', 3, struct partition)
 02111	#define DIOCGETP        _IOR('d', 4, struct partition)
 02112	#define DIOCEJECT       _IO ('d', 5)
 02113	#define DIOCTIMEOUT     _IOW('d', 6, int)
 02114	#define DIOCOPENCT      _IOR('d', 7, int)
 02115	
 02116	#endif /* _S_I_DISK_H */




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/minix/ioctl.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 02200	/*      minix/ioctl.h – вспомогательные определения ioctl.      Автор:  Kees J. Bot
 02201	 *                                                              23 ноября 2002
 02202	 *
 02203	 * Этот файл включен в каждый заголовочный файл, содержащий определения для команды ioctl.
 02204	 */
 02205	
 02206	#ifndef _M_IOCTL_H
 02207	#define _M_IOCTL_H
 02208	
 02209	#ifndef _TYPES_H
 02210	#include <sys/types.h>
 02211	#endif
 02212	
 02213	#if _EM_WSIZE >= 4
 02214	/* В ioctl код команды расположен в младшем слове, а размер параметра - в старшем.
 02215	 * Три старших бита старшего слова кодируют состояние параметра: in, out или
 02216	 * void.
 02217	 */
 02218	#define _IOCPARM_MASK   0x1FFF
 02219	#define _IOC_VOID       0x20000000
 02220	#define _IOCTYPE_MASK   0xFFFF
 02221	#define _IOC_IN         0x40000000
 02222	#define _IOC_OUT        0x80000000
 02223	#define _IOC_INOUT      (_IOC_IN | _IOC_OUT)
 02224	
 02225	#define _IO(x,y)        ((x << 8) | y | _IOC_VOID)
 02226	#define _IOR(x,y,t)     ((x << 8) | y | ((sizeof(t) & _IOCPARM_MASK) << 16) |\
 02227	                                _IOC_OUT)
 02228	#define _IOW(x,y,t)     ((x << 8) | y | ((sizeof(t) & _IOCPARM_MASK) << 16) |\
 02229	                                _IOC_IN)
 02230	#define _IORW(x,y,t)    ((x << 8) | y | ((sizeof(t) & _IOCPARM_MASK) << 16) |\
 02231	                                _IOC_INOUT)
 02232	#else
 02233	/* На 16-разрядной машине сложное кодирование отсутствует. */
 02234	
 02235	#define _IO(x,y)        ((x << 8) | y)
 02236	#define _IOR(x,y,t)     _IO(x,y)
 02237	#define _IOW(x,y,t)     _IO(x,y)
 02238	#define _IORW(x,y,t)    _IO(x,y)
 02239	#endif
 02240	
 02241	int ioctl(int _fd, int _request, void *_data);
 02242	
 02243	#endif /* _M_IOCTL_H */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/minix/config.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 02300	#ifndef _CONFIG_H
 02301	#define _CONFIG_H
 02302	
 02303	/* Номера версии и выпуска Minix. */
 02304	#define OS_RELEASE "3"
 02305	#define OS_VERSION "1.0"
 02306	
 02307	/* Этот файл задает конфигурационные параметры ядра MINIX, файловой системы и менеджера
 02308	 * процессов. Он состоит из двух основных разделов. Первый включает параметры, задаваемые
 02309	 * пользователем. Во втором разделе определены различные внутренние системные параметры,
 02310	 * зависящие от параметров, заданных пользователем.
 02311	 *
 02312	 * Фрагменты файла config.h были помещены в файл sys_config.h, который можно включить
 02313	 * в другие заголовочные файлы, нуждающиеся в конфигурационных данных, но так,
 02314	 * чтобы не загрязнять пользовательское пространство имен. Некоторые редактируемые
 02315	 * значения перемещены туда.
 02316	 *
 02317	 * Это модифицированная версия config.h, предназначенная для компиляции компактной
 02318	 * системы Minix, ограниченной параметрами, описанными в тексте книги.
 02319	 * Полную версию файла config.h, содержащую опущенные параметры, вы найдете в каталоге
 02320	 * с исходным кодом.
 02321	 */
 02322	
 02323	/* Параметр MACHINE (названный _MINIX_MACHINE) можно настроить в файле
 02324	 * <minix/machine.h>.
 02325	 */
 02326	#include <minix/sys_config.h>
 02327	
 02328	#define MACHINE      _MINIX_MACHINE
 02329	
 02330	#define IBM_PC       _MACHINE_IBM_PC
 02331	#define SUN_4        _MACHINE_SUN_4
 02332	#define SUN_4_60     _MACHINE_SUN_4_60
 02333	#define ATARI        _MACHINE_ATARI
 02334	#define MACINTOSH    _MACHINE_MACINTOSH
 02335	
 02336	/* Число записей в таблице процессов, отводимое для процессов, находящихся вне ядра.
 02337	 * Число системных процессов определяет, сколько процессов с особыми привилегиями 
 02338	 * может существовать. Пользовательские процессы совместно используют единый набор. 
 02339	 *
 02340	 * свойств и рассматриваются как единое целое. Это можно изменить в файле sys_config.h.
 02341	 */
 02342	#define NR_PROCS          _NR_PROCS 
 02343	#define NR_SYS_PROCS      _NR_SYS_PROCS
 02344	
 02345	#define NR_BUFS 128
 02346	#define NR_BUF_HASH 128
 02347	
 02348	/* Число заданий контроллеров (/dev/cN device classes). */
 02349	#define NR_CTRLRS          2
 02350	
 02351	/* Включение/отключение второго уровня кэша файловой системы на виртуальном диске. */
 02352	#define ENABLE_CACHE2      0
 02353	
 02354	/* Включение/отключение подкачки процессов */
 02355	#define ENABLE_SWAP        0 
 02356	
 02357	/* Включение/исключение образа /dev/boot из загрузочного образа. 
 02358	 * Не забудьте обновить make-файл в каталоге /usr/src/tools/.
 02359	 */
 02360	#define ENABLE_BOOTDEV     0    /* размещение образа /dev/boot в памяти при загрузке */
 02361	
 02362	/* DMA_SECTORS можно увеличить, чтобы ускорить работу драйверов, работающих с DMA. */
 02363	#define DMA_SECTORS        1    /* размер буфера DMA (>= 1) */
 02364	
 02365	/* Включить или исключить код, обеспечивающий обратную совместимость. */
 02366	#define ENABLE_BINCOMPAT   0    /* для двоичных файлов, использующих устаревшие вызовы */
 02367	#define ENABLE_SRCCOMPAT   0    /* для исходных файлов, использующих устаревшие вызовы */
 02368	
 02369	/* Какой процесс должен получать диагностические данные от ядра и системы? 
 02370	 * Прямая передача на терминал приводит только к отображению вывода. Передача драйверу
 02371	 * журнала буферизует и отображает данные диагностики.
 02372	 */
 02373	#define OUTPUT_PROC_NR  LOG_PROC_NR     /* TTY_PROC_NR или LOG_PROC_NR */
 02374	
 02375	/* NR_CONS, NR_RS_LINES и NR_PTYS определяют число терминалов, которое способна
 02376	 * обслуживать система.
 02377	 */
 02378	#define NR_CONS            4    /* число системных консолей (от 1 до 8) */
 02379	#define NR_RS_LINES        0    /* число терминалов rs232 (от 0 до 4) */
 02380	#define NR_PTYS            0    /* число псевдотерминалов (от 0 до 64) */
 02381	
 02382	/*===========================================================================*
 02383	 *       В последующем коде нет параметров, задаваемых пользователем.        *
 02384	 *===========================================================================*/
 02385	/* Задайте тип микросхемы (CHIP) в зависимости от выбранного компьютера. Символ CHIP
 02386	 * на самом деле указывает не только на процессор. Например, от машин, для которых
 02387	 * CHIP == INTEL, ожидается наличие контроллеров прерываний 8259A и прочих свойств,
 02388	 * присущих компьютерам IBM PC/XT/AT/386 */
 02389	#define INTEL             _CHIP_INTEL   /* Тип микросхемы для PC, XT, AT, 386 и клонов */
 02390	#define M68000            _CHIP_M68000  /* Тип микросхемы для Atari, Amiga, Macintosh  */
 02391	#define SPARC             _CHIP_SPARC   /* Тип микросхемы для SUN-4 (напр., SPARCstation)  */
 02392	
 02393	/* Задание типа FP_FORMAT согласно выбранной машине, hw или sw    */
 02394	#define FP_NONE  _FP_NONE       /* нет поддержки вещественной арифметики                */
 02395	#define FP_IEEE  _FP_IEEE       /* соответствие стандарту вещественных чисел IEEE       */
 02396	
 02397	/* _MINIX_CHIP определен в sys_config.h. */
 02398	#define CHIP    _MINIX_CHIP
 02399	
 02400	/* _MINIX_FP_FORMAT определен в sys_config.h. */
 02401	#define FP_FORMAT       _MINIX_FP_FORMAT
 02402	
 02403	/* _ASKDEV и _FASTLOAD определены в sys_config.h. */
 02404	#define ASKDEV _ASKDEV
 02405	#define FASTLOAD _FASTLOAD
 02406	
 02407	#endif /* _CONFIG_H */



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/minix/sys_config.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 02500	#ifndef _MINIX_SYS_CONFIG_H
 02501	#define _MINIX_SYS_CONFIG_H 1
 02502	
 02503	/* Это модифицированная версия sys_config.h, предназначенная для компиляции компактной 
 02504	 * системы Minix, ограниченной параметрами, описанными в тексте книги.
 02505	 * Полную версию файла config.h, содержащую опущенные параметры, вы найдете в каталоге
 02506	 * с исходным кодом.
 02507	 */
 02508	
 02509	/*===========================================================================*
 02510	 *        Этот раздел содержит параметры, задаваемые пользователем           *
 02511	 *===========================================================================*/
 02512	#define _MINIX_MACHINE       _MACHINE_IBM_PC
 02513	
 02514	#define _MACHINE_IBM_PC             1   /* любая система на базе 8088 или 80x86  */
 02515	
 02516	/* Размер слова в байтах (константа, равная sizeof(int)). */
 02517	#if __ACK__ || __GNUC__
 02518	#define _WORD_SIZE      _EM_WSIZE
 02519	#define _PTR_SIZE       _EM_WSIZE
 02520	#endif
 02521	
 02522	#define _NR_PROCS       64
 02523	#define _NR_SYS_PROCS   32
 02524	
 02525	/* Задайте тип микросхемы (CHIP) в зависимости от выбранного компьютера. Символ CHIP
 02526	 * на самом деле указывает не только на процессор. Например, от машин, для которых
 02527	 * CHIP == INTEL, ожидается наличие контроллеров прерываний 8259A и прочих свойств,
 02528	 * присущих компьютерам IBM PC/XT/AT/386 */
 02529	#define _CHIP_INTEL     1       /* Тип микросхемы для PC, XT, AT, 386 и клонов */
 02530	
 02531	/* Задание типа FP_FORMAT согласно выбранной машине, hw или sw    */
 02532	#define _FP_NONE        0       /* нет поддержки вещественной арифметики                */
 02533	#define _FP_IEEE        1       /* соответствие стандарту вещественных чисел IEEE     */
 02534	
 02535	#define _MINIX_CHIP          _CHIP_INTEL
 02536	
 02537	#define _MINIX_FP_FORMAT   _FP_NONE
 02538	
 02539	#ifndef _MINIX_MACHINE
 02540	error "In <minix/sys_config.h> please define _MINIX_MACHINE"
 02541	#endif
 02542	
 02543	#ifndef _MINIX_CHIP
 02544	error "In <minix/sys_config.h> please define _MINIX_MACHINE to have a legal value"
 02545	#endif
 02546	
 02547	#if (_MINIX_MACHINE == 0)
 02548	error "_MINIX_MACHINE has incorrect value (0)"
 02549	#endif
 02550	
 02551	#endif /* _MINIX_SYS_CONFIG_H */
 02552	
 02553	


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/minix/const.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 02600	/* Copyright (C) 2001 Prentice-Hall, Inc. Замечание об авторских правах см. в файле
 02601	 * /usr/src/LICENSE.
 02602	 */
 02603	
 02604	#ifndef CHIP
 02605	#error CHIP is not defined
 02606	#endif
 02607	
 02608	#define EXTERN        extern    /* используется в файлах *.h */
 02609	#define PRIVATE       static    /* PRIVATE x ограничивает область видимости x */
 02610	#define PUBLIC                  /* PUBLIC - противоположность PRIVATE */
 02611	#define FORWARD       static    /* некоторые компиляторы требуют этого для 'static'*/
 02612	
 02613	#define TRUE               1    /* для преобразования целых значений в логические */
 02614	#define FALSE              0    /* для преобразования целых значений в логические */
 02615	
 02616	#define HZ                60    /* частота таймера (программно устанавливаемая на IBM-PC) */
 02617	
 02618	#define SUPER_USER (uid_t) 0    /* uid_t суперпользователя */
 02619	
 02620	/* Устройства. */
 02621	#define MAJOR              8    /* главное устройство = (dev>>MAJOR) & 0377 */
 02622	#define MINOR              0    /* вспомогательное устройство = (dev>>MINOR) & 0377 */
 02623	
 02624	#define NULL     ((void *)0)    /* нулевой указатель */
 02625	#define CPVEC_NR          16    /* максимальное число записей в запросе SYS_VCOPY */
 02626	#define CPVVEC_NR         64    /* максимальное число записей в запросе SYS_VCOPY */
 02627	#define NR_IOREQS       MIN(NR_BUFS, 64)
 02628	                                /* максимальное число записей в запросе ввода-вывода */
 02629	
 02630	/* Константы передачи сообщений. */
 02631	#define MESS_SIZE (sizeof(message))     /* здесь может понадобиться usizeof файловой системы */
 02632	#define NIL_MESS ((message *) 0)        /* нулевой указатель */
 02633	
 02634	/* Константы, связанные с памятью. */
 02635	#define SEGMENT_TYPE  0xFF00    /* битовая маска для получения типа сегмента */
 02636	#define SEGMENT_INDEX 0x00FF    /* битовая маска для получения индекса сегмента */
 02637	
 02638	#define LOCAL_SEG     0x0000    /* флаги, индицирующие сегмент локальной памяти */
 02639	#define NR_LOCAL_SEGS      3    /* число локальных сегментов процесса (фиксированно) */
 02640	#define T                  0    /* proc[i].mem_map[T] для кода */
 02641	#define D                  1    /* proc[i].mem_map[D] для данных */
 02642	#define S                  2    /* proc[i].mem_map[S] для стека */
 02643	
 02644	#define REMOTE_SEG    0x0100    /* флаги, индицирующие сегмент удаленной памяти */
 02645	#define NR_REMOTE_SEGS     3    /* число удаленных областей памяти (переменно) */
 02646	
 02647	#define BIOS_SEG      0x0200    /* флаги, индицирующие сегмент памяти BIOS */
 02648	#define NR_BIOS_SEGS       3    /* число областей памяти BIOS (переменно) */
 02649	
 02650	#define PHYS_SEG      0x0400    /* флаги, индицирующие всю физическую памяти */
 02651	
 02652	/* Метки, используемые для отключения разделов кода по различным причинам. */
 02653	#define DEAD_CODE          0    /* неиспользуемый код в нормальной конфигурации */
 02654	#define FUTURE_CODE        0    /* новый код, подлежащий активации и последующему тестированию */
 02655	#define TEMP_CODE          1    /* активный код, подлежащий последующему удалению */
 02656	
 02657	/* Длина имени процесса в таблице менеджера процессов, включая '\0'. */
 02658	#define PROC_NAME_LEN   16
 02659	
 02660	/* Разное */
 02661	#define BYTE            0377    /* маска для 8 бит */
 02662	#define READING            0    /* копирование данных пользователю */
 02663	#define WRITING            1    /* копирование данных от пользователя */
 02664	#define NO_NUM        0x8000    /* используется в качестве численного аргумента для panic() */
 02665	#define NIL_PTR   (char *) 0    /* полезное "многоцелевое" выражение */
 02666	#define HAVE_SCATTERED_IO  1    /* разрозненный ввод-вывод теперь стандартный */
 02667	
 02668	/* Макросы. */
 02669	#define MAX(a, b)   ((a) > (b) ? (a) :  (b))
 02670	#define MIN(a, b)   ((a) < (b) ? (a) :  (b))
 02671	
 02672	/* Память выделяется в кликах. */
 02673	#if (CHIP == INTEL)
 02674	#define CLICK_SIZE      1024    /* единицы выделения памяти */
 02675	#define CLICK_SHIFT       10    /* log2 размера CLICK_SIZE */
 02676	#endif
 02677	
 02678	#if (CHIP == SPARC) || (CHIP == M68000)
 02679	#define CLICK_SIZE      4096    /* устройство, на котором выделяется память */
 02680	#define CLICK_SHIFT       12    /* log2 размера CLICK_SIZE */
 02681	#endif
 02682	
 02683	/* Преобразование кликов в байты и наоборот */
 02684	#define HCLICK_SHIFT       4    /* log2 размера HCLICK_SIZE */
 02685	#define HCLICK_SIZE       16    /* магическое число преобразования аппаратного сегмента */
 02686	#if CLICK_SIZE >= HCLICK_SIZE
 02687	#define click_to_hclick(n) ((n) << (CLICK_SHIFT - HCLICK_SHIFT))
 02688	#else
 02689	#define click_to_hclick(n) ((n) >> (HCLICK_SHIFT - CLICK_SHIFT))
 02690	#endif
 02691	#define hclick_to_physb(n) ((phys_bytes) (n) << HCLICK_SHIFT)
 02692	#define physb_to_hclick(n) ((n) >> HCLICK_SHIFT)
 02693	
 02694	#define ABS             -999    /* данный процесс использует абсолютную память */
 02695	
 02696	/* Флаговые биты индексного узла для i_mode. */
 02697	#define I_TYPE          0170000 /* тип индексного узла */
 02698	#define I_REGULAR       0100000 /* обычный файл, не каталог и не специальный файл */
 02699	#define I_BLOCK_SPECIAL 0060000 /* блочный специальный файл */
 02700	#define I_DIRECTORY     0040000 /* файл, являющийся каталогом */
 02701	#define I_CHAR_SPECIAL  0020000 /* символьный специальный файл */
 02702	#define I_NAMED_PIPE    0010000 /* именованный канал (FIFO) */
 02703	#define I_SET_UID_BIT   0004000 /* установить эффективный идентификатор uid_t при исполнении */
 02704	#define I_SET_GID_BIT   0002000 /* установить эффективный идентификатор gid_t при исполнении */
 02705	#define ALL_MODES       0006777 /* все биты для пользователя, группы и прочих */
 02706	#define RWX_MODES       0000777 /* биты режима только для RWX */
 02707	#define R_BIT           0000004 /* бит защиты Rwx */
 02708	#define W_BIT           0000002 /* бит защиты rWx */
 02709	#define X_BIT           0000001 /* бит защиты rwX */
 02710	#define I_NOT_ALLOC     0000000 /* индексный узел свободен */
 02711	
 02712	/* Флаг, используемый только в аргументе flags dev_open. */
 02713	#define RO_BIT          0200000 /* Открыть устройство только на чтение; если доступна запись, неудача */
 02714	
 02715	/* Некоторые пределы. */
 02716	#define MAX_BLOCK_NR  ((block_t) 077777777)     /* максимальный размер блока */
 02717	#define HIGHEST_ZONE   ((zone_t) 077777777)     /* Максимальный размер зоны */
 02718	#define MAX_INODE_NR ((ino_t) 037777777777)     /* Максимальный номер индексного узла */
 02719	#define MAX_FILE_POS ((off_t) 037777777777)     /* Максимальное допустимое смещение файла */
 02720	
 02721	#define NO_BLOCK              ((block_t) 0)     /* отсутствие номера блока */
 02722	#define NO_ENTRY                ((ino_t) 0)     /* отсутствие записи каталога */
 02723	#define NO_ZONE                ((zone_t) 0)     /* отсутствие номера зоны */
 02724	#define NO_DEV                  ((dev_t) 0)     /* отсутствие номера устройства */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/minix/type.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 02800	#ifndef _TYPE_H
 02801	#define _TYPE_H
 02802	
 02803	#ifndef _MINIX_SYS_CONFIG_H
 02804	#include <minix/sys_config.h>
 02805	#endif
 02806	
 02807	#ifndef _TYPES_H
 02808	#include <sys/types.h>
 02809	#endif
 02810	
 02811	/* Определения типов. */
 02812	typedef unsigned int vir_clicks;        /* виртуальный адрес/длина в кликах */
 02813	typedef unsigned long phys_bytes;       /* физический адрес/длина в байтах */
 02814	typedef unsigned int phys_clicks;       /* физический адрес/длина в байтах */
 02815	
 02816	#if (_MINIX_CHIP == _CHIP_INTEL)
 02817	typedef unsigned int vir_bytes; /* виртуальные адреса и длины в байтах */
 02818	#endif
 02819	
 02820	#if (_MINIX_CHIP == _CHIP_M68000)
 02821	typedef unsigned long vir_bytes;/* виртуальные адреса и длины в байтах */
 02822	#endif
 02823	
 02824	#if (_MINIX_CHIP == _CHIP_SPARC)
 02825	typedef unsigned long vir_bytes;/* виртуальные адреса и длины в байтах */
 02826	#endif
 02827	
 02828	/* Карта памяти для локальных сегментов кода, стека и данных. */
 02829	struct mem_map {
 02830	  vir_clicks mem_vir;           /* виртуальный адрес */
 02831	  phys_clicks mem_phys;         /* физический адрес */
 02832	  vir_clicks mem_len;           /* длина */
 02833	};
 02834	
 02835	/* Карта памяти для удаленных областей памяти, например, для виртуального диска. */
 02836	struct far_mem {
 02837	  int in_use;                   /* используемая запись, если не ноль */
 02838	  phys_clicks mem_phys;         /* физический адрес */
 02839	  vir_clicks mem_len;           /* длина */
 02840	};
 02841	
 02842	/* Структура для виртуального копирования посредством вектора запросов. */
 02843	struct vir_addr {
 02844	  int proc_nr;
 02845	  int segment;
 02846	  vir_bytes offset;
 02847	};
 02848	
 02849	#define phys_cp_req vir_cp_req 
 02850	struct vir_cp_req {
 02851	  struct vir_addr src;
 02852	  struct vir_addr dst;
 02853	  phys_bytes count;
 02854	};
 02855	
 02856	typedef struct {
 02857	  vir_bytes iov_addr;           /* адрес буфера ввода-вывода */
 02858	  vir_bytes iov_size;           /* размер буфера ввода-вывода */
 02859	} iovec_t;
 02860	
 02861	/* Менеджер процессов передает адрес структуры этого типа ядру, когда 
 02862	 * при обработке сигнала вызывается функция sys_sendsig(). Структура 
 02863	 * содержит всю информацию, необходимую ядру для создания стека
 02864	 * сигналов.
 02865	 */
 02866	struct sigmsg {
 02867	  int sm_signo;                 /* номер обрабатываемого сигнала */
 02868	  unsigned long sm_mask;        /* маска для восстановления при возврате из обработчика */
 02869	  vir_bytes sm_sighandler;      /* адрес обработчика */
 02870	  vir_bytes sm_sigreturn;       /* адрес _sigreturn в библиотеке C */
 02871	  vir_bytes sm_stkptr;          /* указатель стека пользователя */
 02872	};
 02873	
 02874	/* Используется для получения системной информации через SYS_GETINFO. */
 02875	struct kinfo {
 02876	  phys_bytes code_base;         /* базовый адрес кода ядра */
 02877	  phys_bytes code_size;         
 02878	  phys_bytes data_base;         /* бaзовый адрес данных ядра */
 02879	  phys_bytes data_size;
 02880	  vir_bytes proc_addr;          /* виртуальный адрес таблицы процессов */
 02881	  phys_bytes kmem_base;         /* схема памяти ядра (/dev/kmem) */
 02882	  phys_bytes kmem_size;
 02883	  phys_bytes bootdev_base;      /* загрузочное устройство (/dev/boot) */
 02884	  phys_bytes bootdev_size;
 02885	  phys_bytes bootdev_mem;
 02886	  phys_bytes params_base;       /* параметры, передаваемые монитором загрузки */
 02887	  phys_bytes params_size;
 02888	  int nr_procs;                 /* число пользовательских процессов */
 02889	  int nr_tasks;                 /* число заданий ядра */
 02890	  char release[6];              /* номер выпуска ядра */
 02891	  char version[6];              /* номер версии ядра */
 02892	  int relocking;                /* проверка повторной блокировки (для отладки) */
 02893	};
 02894	
 02895	struct machine {
 02896	  int pc_at;
 02897	  int ps_mca;
 02898	  int processor;
 02899	  int protected;
 02900	  int vdu_ega;
 02901	  int vdu_vga;
 02902	};
 02903	
 02904	#endif /* _TYPE_H */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/minix/ipc.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 03000	#ifndef _IPC_H
 03001	#define _IPC_H
 03002	
 03003	/*==========================================================================* 
 03004	 * Типы, относящиеся к сообщениям.                                              *
 03005	 *==========================================================================*/ 
 03006	
 03007	#define M1                 1
 03008	#define M3                 3
 03009	#define M4                 4
 03010	#define M3_STRING         14
 03011	
 03012	typedef struct {int m1i1, m1i2, m1i3; char *m1p1, *m1p2, *m1p3;} mess_1;
 03013	typedef struct {int m2i1, m2i2, m2i3; long m2l1, m2l2; char *m2p1;} mess_2;
 03014	typedef struct {int m3i1, m3i2; char *m3p1; char m3ca1[M3_STRING];} mess_3;
 03015	typedef struct {long m4l1, m4l2, m4l3, m4l4, m4l5;} mess_4;
 03016	typedef struct {short m5c1, m5c2; int m5i1, m5i2; long m5l1, m5l2, m5l3;}mess_5;
 03017	typedef struct {int m7i1, m7i2, m7i3, m7i4; char *m7p1, *m7p2;} mess_7;
 03018	typedef struct {int m8i1, m8i2; char *m8p1, *m8p2, *m8p3, *m8p4;} mess_8;
 03019	
 03020	typedef struct {
 03021	  int m_source;                 /* отправитель сообщения */
 03022	  int m_type;                   /* тип сообщения */
 03023	  union {
 03024	        mess_1 m_m1;
 03025	        mess_2 m_m2;
 03026	        mess_3 m_m3;
 03027	        mess_4 m_m4;
 03028	        mess_5 m_m5;
 03029	        mess_7 m_m7;
 03030	        mess_8 m_m8;
 03031	  } m_u;
 03032	} message;
 03033	
 03034	/* следующие директивы define задают имена полезным членам. */
 03035	#define m1_i1  m_u.m_m1.m1i1
 03036	#define m1_i2  m_u.m_m1.m1i2
 03037	#define m1_i3  m_u.m_m1.m1i3
 03038	#define m1_p1  m_u.m_m1.m1p1
 03039	#define m1_p2  m_u.m_m1.m1p2
 03040	#define m1_p3  m_u.m_m1.m1p3
 03041	
 03042	#define m2_i1  m_u.m_m2.m2i1
 03043	#define m2_i2  m_u.m_m2.m2i2
 03044	#define m2_i3  m_u.m_m2.m2i3
 03045	#define m2_l1  m_u.m_m2.m2l1
 03046	#define m2_l2  m_u.m_m2.m2l2
 03047	#define m2_p1  m_u.m_m2.m2p1
 03048	
 03049	#define m3_i1  m_u.m_m3.m3i1
 03050	#define m3_i2  m_u.m_m3.m3i2
 03051	#define m3_p1  m_u.m_m3.m3p1
 03052	#define m3_ca1 m_u.m_m3.m3ca1
 03053	
 03054	#define m4_l1  m_u.m_m4.m4l1
 03055	#define m4_l2  m_u.m_m4.m4l2
 03056	#define m4_l3  m_u.m_m4.m4l3
 03057	#define m4_l4  m_u.m_m4.m4l4
 03058	#define m4_l5  m_u.m_m4.m4l5
 03059	
 03060	#define m5_c1  m_u.m_m5.m5c1
 03061	#define m5_c2  m_u.m_m5.m5c2
 03062	#define m5_i1  m_u.m_m5.m5i1
 03063	#define m5_i2  m_u.m_m5.m5i2
 03064	#define m5_l1  m_u.m_m5.m5l1
 03065	#define m5_l2  m_u.m_m5.m5l2
 03066	#define m5_l3  m_u.m_m5.m5l3
 03067	
 03068	#define m7_i1  m_u.m_m7.m7i1
 03069	#define m7_i2  m_u.m_m7.m7i2
 03070	#define m7_i3  m_u.m_m7.m7i3
 03071	#define m7_i4  m_u.m_m7.m7i4
 03072	#define m7_p1  m_u.m_m7.m7p1
 03073	#define m7_p2  m_u.m_m7.m7p2
 03074	
 03075	#define m8_i1  m_u.m_m8.m8i1
 03076	#define m8_i2  m_u.m_m8.m8i2
 03077	#define m8_p1  m_u.m_m8.m8p1
 03078	#define m8_p2  m_u.m_m8.m8p2
 03079	#define m8_p3  m_u.m_m8.m8p3
 03080	#define m8_p4  m_u.m_m8.m8p4
 03081	
 03082	/*==========================================================================* 
 03083	 * Система реального времени MINIX (межпроцессное взаимодействие).                                           *
 03084	 *==========================================================================*/ 
 03085	
 03086	/* Скрытие имен во избежание "загрязнения" пространства имен. */
 03087	#define echo            _echo
 03088	#define notify          _notify
 03089	#define sendrec         _sendrec
 03090	#define receive         _receive
 03091	#define send            _send
 03092	#define nb_receive      _nb_receive
 03093	#define nb_send         _nb_send
 03094	
 03095	_PROTOTYPE( int echo, (message *m_ptr)                                  );
 03096	_PROTOTYPE( int notify, (int dest)                                      );
 03097	_PROTOTYPE( int sendrec, (int src_dest, message *m_ptr)                 );
 03098	_PROTOTYPE( int receive, (int src, message *m_ptr)                      );
 03099	_PROTOTYPE( int send, (int dest, message *m_ptr)                        );
    03100	_PROTOTYPE( int nb_receive, (int src, message *m_ptr)                   );
 03101	_PROTOTYPE( int nb_send, (int dest, message *m_ptr)                     );
 03102	
 03103	#endif /* _IPC_H */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/minix/syslib.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 03200	/* Прототипы функций системной библиотеки. */
 03201	
 03202	#ifndef _SYSLIB_H
 03203	#define _SYSLIB_H
 03204	
 03205	#ifndef _TYPES_H
 03206	#include <sys/types.h>
 03207	#endif
 03208	
 03209	#ifndef _IPC_H
 03210	#include <minix/ipc.h>
 03211	#endif
 03212	
 03213	#ifndef _DEVIO_H
 03214	#include <minix/devio.h>
 03215	#endif
 03216	
 03217	/* Упреждающее объявление */
 03218	struct reg86u;
 03219	
 03220	#define SYSTASK SYSTEM
 03221	
 03222	/*==========================================================================* 
 03223	 * Системная библиотека Minix.                                              *
 03224	 *==========================================================================*/ 
 03225	_PROTOTYPE( int _taskcall, (int who, int syscallnr, message *msgptr));
 03226	
 03227	_PROTOTYPE( int sys_abort, (int how, ...));
 03228	_PROTOTYPE( int sys_exec, (int proc, char *ptr,  
 03229	                                char *aout, vir_bytes initpc));
 03230	_PROTOTYPE( int sys_fork, (int parent, int child));
 03231	_PROTOTYPE( int sys_newmap, (int proc, struct mem_map *ptr));
 03232	_PROTOTYPE( int sys_exit, (int proc));
 03233	_PROTOTYPE( int sys_trace, (int req, int proc, long addr, long *data_p));
 03234	
 03235	_PROTOTYPE( int sys_svrctl, (int proc, int req, int priv,vir_bytes argp));
 03236	_PROTOTYPE( int sys_nice, (int proc, int priority));
 03237	
 03238	_PROTOTYPE( int sys_int86, (struct reg86u *reg86p));
 03239	
 03240	/* интерфейс системного вызова sys_sdevio(). */
 03241	#define sys_insb(port, proc_nr, buffer, count) \
 03242	        sys_sdevio(DIO_INPUT, port, DIO_BYTE, proc_nr, buffer, count)
 03243	#define sys_insw(port, proc_nr, buffer, count) \
 03244	        sys_sdevio(DIO_INPUT, port, DIO_WORD, proc_nr, buffer, count)
 03245	#define sys_outsb(port, proc_nr, buffer, count) \
 03246	        sys_sdevio(DIO_OUTPUT, port, DIO_BYTE, proc_nr, buffer, count)
 03247	#define sys_outsw(port, proc_nr, buffer, count) \
 03248	        sys_sdevio(DIO_OUTPUT, port, DIO_WORD, proc_nr, buffer, count)
 03249	_PROTOTYPE( int sys_sdevio, (int req, long port, int type, int proc_nr,
 03250	        void *buffer, int count));
 03251	
 03252	/* Функции таймера: получение системного времени или планирование/сброс таймера. */
 03253	_PROTOTYPE( int sys_times, (int proc_nr, clock_t *ptr));
 03254	_PROTOTYPE(int sys_setalarm, (clock_t exp_time, int abs_time));
 03255	
 03256	/* Интерфейс системного вызова sys_irqctl(). */
 03257	#define sys_irqdisable(hook_id) \
 03258	    sys_irqctl(IRQ_DISABLE, 0, 0, hook_id) 
 03259	#define sys_irqenable(hook_id) \
 03260	    sys_irqctl(IRQ_ENABLE, 0, 0, hook_id) 
 03261	#define sys_irqsetpolicy(irq_vec, policy, hook_id) \
 03262	    sys_irqctl(IRQ_SETPOLICY, irq_vec, policy, hook_id)
 03263	#define sys_irqrmpolicy(irq_vec, hook_id) \
 03264	    sys_irqctl(IRQ_RMPOLICY, irq_vec, 0, hook_id)
 03265	_PROTOTYPE ( int sys_irqctl, (int request, int irq_vec, int policy,
 03266	    int *irq_hook_id) );
 03267	
 03268	/* Интерфейс системных вызовов sys_vircopy() и sys_physcopy(). */
 03269	#define sys_biosin(bios_vir, dst_vir, bytes) \
 03270	        sys_vircopy(SELF, BIOS_SEG, bios_vir, SELF, D, dst_vir, bytes)
 03271	#define sys_biosout(src_vir, bios_vir, bytes) \
 03272	        sys_vircopy(SELF, D, src_vir, SELF, BIOS_SEG, bios_vir, bytes)
 03273	#define sys_datacopy(src_proc, src_vir, dst_proc, dst_vir, bytes) \
 03274	        sys_vircopy(src_proc, D, src_vir, dst_proc, D, dst_vir, bytes)
 03275	#define sys_textcopy(src_proc, src_vir, dst_proc, dst_vir, bytes) \
 03276	        sys_vircopy(src_proc, T, src_vir, dst_proc, T, dst_vir, bytes)
 03277	#define sys_stackcopy(src_proc, src_vir, dst_proc, dst_vir, bytes) \
 03278	        sys_vircopy(src_proc, S, src_vir, dst_proc, S, dst_vir, bytes)
 03279	_PROTOTYPE(int sys_vircopy, (int src_proc, int src_seg, vir_bytes src_vir,
 03280	        int dst_proc, int dst_seg, vir_bytes dst_vir, phys_bytes bytes));
 03281	
 03282	#define sys_abscopy(src_phys, dst_phys, bytes) \
 03283	        sys_physcopy(NONE, PHYS_SEG, src_phys, NONE, PHYS_SEG, dst_phys, bytes)
 03284	_PROTOTYPE(int sys_physcopy, (int src_proc, int src_seg, vir_bytes src_vir,
 03285	        int dst_proc, int dst_seg, vir_bytes dst_vir, phys_bytes bytes));
 03286	_PROTOTYPE(int sys_memset, (unsigned long pattern, 
 03287	                phys_bytes base, phys_bytes bytes));
 03288	
 03289	/* Вызовы векторного виртуального/физического копирования. */
 03290	#if DEAD_CODE           /* библиотечная часть еще не реализована */
 03291	_PROTOTYPE(int sys_virvcopy, (phys_cp_req *vec_ptr,int vec_size,int *nr_ok));
 03292	_PROTOTYPE(int sys_physvcopy, (phys_cp_req *vec_ptr,int vec_size,int *nr_ok));
 03293	#endif
 03294	
 03295	_PROTOTYPE(int sys_umap, (int proc_nr, int seg, vir_bytes vir_addr,
 03296	         vir_bytes bytes, phys_bytes *phys_addr));
 03297	_PROTOTYPE(int sys_segctl, (int *index, u16_t *seg, vir_bytes *off,
 03298	        phys_bytes phys, vir_bytes size));
 03299	
 03300	/* Интерфейс системного вызова sys_getinfo(). */
 03301	#define sys_getkmessages(dst)   sys_getinfo(GET_KMESSAGES, dst, 0,0,0)
 03302	#define sys_getkinfo(dst)       sys_getinfo(GET_KINFO, dst, 0,0,0)
 03303	#define sys_getmachine(dst)     sys_getinfo(GET_MACHINE, dst, 0,0,0)
 03304	#define sys_getproctab(dst)     sys_getinfo(GET_PROCTAB, dst, 0,0,0)
 03305	#define sys_getprivtab(dst)     sys_getinfo(GET_PRIVTAB, dst, 0,0,0)
 03306	#define sys_getproc(dst,nr)     sys_getinfo(GET_PROC, dst, 0,0, nr)
 03307	#define sys_getrandomness(dst)  sys_getinfo(GET_RANDOMNESS, dst, 0,0,0)
 03308	#define sys_getimage(dst)       sys_getinfo(GET_IMAGE, dst, 0,0,0)
 03309	#define sys_getirqhooks(dst)    sys_getinfo(GET_IRQHOOKS, dst, 0,0,0)
 03310	#define sys_getmonparams(v,vl)  sys_getinfo(GET_MONPARAMS, v,vl, 0,0)
 03311	#define sys_getschedinfo(v1,v2) sys_getinfo(GET_SCHEDINFO, v1,0, v2,0)
 03312	#define sys_getlocktimings(dst) sys_getinfo(GET_LOCKTIMING, dst, 0,0,0)
 03313	#define sys_getbiosbuffer(virp, sizep) sys_getinfo(GET_BIOSBUFFER, virp, \
 03314	        sizeof(*virp), sizep, sizeof(*sizep))
 03315	_PROTOTYPE(int sys_getinfo, (int request, void *val_ptr, int val_len,
 03316	                                 void *val_ptr2, int val_len2)          );
 03317	
 03318	/* Контроль сигналов. */
 03319	_PROTOTYPE(int sys_kill, (int proc, int sig) );
 03320	_PROTOTYPE(int sys_sigsend, (int proc_nr, struct sigmsg *sig_ctxt) ); 
 03321	_PROTOTYPE(int sys_sigreturn, (int proc_nr, struct sigmsg *sig_ctxt) );
 03322	_PROTOTYPE(int sys_getksig, (int *k_proc_nr, sigset_t *k_sig_map) ); 
 03323	_PROTOTYPE(int sys_endksig, (int proc_nr) );
 03324	
 03325	/* ПРИМЕЧАНИЕ: для различения типов 'byte', 'word' и 'long' данных, вводимых/выводимых 
 03326	 * с/на устройства, были использованы два подхода. В последнем задействуется #define, что делает
 03327	 * реализацию компактной, но освобождает от статической проверки типов.
 03328	 */
 03329	_PROTOTYPE(int sys_voutb, (pvb_pair_t *pvb_pairs, int nr_ports)         );
 03330	_PROTOTYPE(int sys_voutw, (pvw_pair_t *pvw_pairs, int nr_ports)         );
 03331	_PROTOTYPE(int sys_voutl, (pvl_pair_t *pvl_pairs, int nr_ports)         );
 03332	_PROTOTYPE(int sys_vinb, (pvb_pair_t *pvb_pairs, int nr_ports)          );
 03333	_PROTOTYPE(int sys_vinw, (pvw_pair_t *pvw_pairs, int nr_ports)          );
 03334	_PROTOTYPE(int sys_vinl, (pvl_pair_t *pvl_pairs, int nr_ports)          );
 03335	
 03336	/* Интерфейс системного вызова sys_out(). */
 03337	#define sys_outb(p,v)   sys_out((p), (unsigned long) (v), DIO_BYTE)
 03338	#define sys_outw(p,v)   sys_out((p), (unsigned long) (v), DIO_WORD)
 03339	#define sys_outl(p,v)   sys_out((p), (unsigned long) (v), DIO_LONG)
 03340	_PROTOTYPE(int sys_out, (int port, unsigned long value, int type)       ); 
 03341	
 03342	/* Интерфейс системного вызова sys_in(). */
 03343	#define sys_inb(p,v)    sys_in((p), (unsigned long*) (v), DIO_BYTE)
 03344	#define sys_inw(p,v)    sys_in((p), (unsigned long*) (v), DIO_WORD)
 03345	#define sys_inl(p,v)    sys_in((p), (unsigned long*) (v), DIO_LONG)
 03346	_PROTOTYPE(int sys_in, (int port, unsigned long *value, int type)       );
 03347	
 03348	#endif /* _SYSLIB_H */
 03349	

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/minix/sysutil.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 03400	#ifndef _EXTRALIB_H
 03401	#define _EXTRALIB_H
 03402	
 03403	/* Дополнительные определения системной библиотеки для поддержки драйверов устройств и серверов.
 03404	 *
 03405	 * Создан: 
 03406	 *      15 марта 2004, Jorrit N. Herder
 03407	 *
 03408	 * Изменения: 
 03409	 *      31 мая 2005:  добавлено printf, kputc (перенесено из syslib)
 03410	 *      31 мая 2005:  добавлено getuptime
 03411	 *      18 марта 2005:  добавлено tickdelay
 03412	 *      01 октября 2004:  добавлено env_parse, env_prefix, env_panic
 03413	 *      13 июля 2004:  добавлено fkey_ctl
 03414	 *      28 апреля 2004:  добавлено report, panic 
 03415	 *      31 марта 2004:  настройка по аналогии с другими библиотеками, такими, как syslib
 03416	 */
 03417	
 03418	/*==========================================================================* 
 03419	 * Различные вспомогательные функции.
 03420	 *==========================================================================*/ 
 03421	
 03422	/* Значения, возвращаемые при разборе переменных окружения. */
 03423	#define EP_BUF_SIZE   128       /* локальный буфер для переменной окружения */
 03424	#define EP_UNSET        0       /* значение не задано */
 03425	#define EP_OFF          1       /* значение = "выключено" */
 03426	#define EP_ON           2       /* значение = "включено" (или поле оставлено пустым) */
 03427	#define EP_SET          3       /* значение = 1: 2: 3 (непустое поле) */
 03428	#define EP_EGETKENV     4       /* неудачный вызов sys_getkenv() */
 03429	
 03430	_PROTOTYPE( void env_setargs, (int argc, char *argv[])                  );
 03431	_PROTOTYPE( int env_get_param, (char *key, char *value, int max_size)   );
 03432	_PROTOTYPE( int env_prefix, (char *env, char *prefix)                   );
 03433	_PROTOTYPE( void env_panic, (char *key)                                 );
 03434	_PROTOTYPE( int env_parse, (char *env, char *fmt, int field, long *param,
 03435	                                long min, long max)                     );
 03436	
 03437	#define fkey_map(fkeys, sfkeys) fkey_ctl(FKEY_MAP, (fkeys), (sfkeys))
 03438	#define fkey_unmap(fkeys, sfkeys) fkey_ctl(FKEY_UNMAP, (fkeys), (sfkeys))
 03439	#define fkey_events(fkeys, sfkeys) fkey_ctl(FKEY_EVENTS, (fkeys), (sfkeys))
 03440	_PROTOTYPE( int fkey_ctl, (int req, int *fkeys, int *sfkeys)            );
 03441	
 03442	_PROTOTYPE( int printf, (const char *fmt, ...));
 03443	_PROTOTYPE( void kputc, (int c));
 03444	_PROTOTYPE( void report, (char *who, char *mess, int num));
 03445	_PROTOTYPE( void panic, (char *who, char *mess, int num));
 03446	_PROTOTYPE( int getuptime, (clock_t *ticks));
 03447	_PROTOTYPE( int tickdelay, (clock_t ticks));
 03448	
 03449	#endif /* _EXTRALIB_H */
 03450	





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/minix/callnr.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 03500	#define NCALLS            91    /* число разрешенных системных вызовов */
 03501	
 03502	#define EXIT               1 
 03503	#define FORK               2 
 03504	#define READ               3 
 03505	#define WRITE              4 
 03506	#define OPEN               5 
 03507	#define CLOSE              6 
 03508	#define WAIT               7
 03509	#define CREAT              8 
 03510	#define LINK               9 
 03511	#define UNLINK            10 
 03512	#define WAITPID           11
 03513	#define CHDIR             12 
 03514	#define TIME              13
 03515	#define MKNOD             14 
 03516	#define CHMOD             15 
 03517	#define CHOWN             16 
 03518	#define BRK               17
 03519	#define STAT              18 
 03520	#define LSEEK             19
 03521	#define GETPID            20
 03522	#define MOUNT             21 
 03523	#define UMOUNT            22 
 03524	#define SETUID            23
 03525	#define GETUID            24
 03526	#define STIME             25
 03527	#define PTRACE            26
 03528	#define ALARM             27
 03529	#define FSTAT             28 
 03530	#define PAUSE             29
 03531	#define UTIME             30 
 03532	#define ACCESS            33 
 03533	#define SYNC              36 
 03534	#define KILL              37
 03535	#define RENAME            38
 03536	#define MKDIR             39
 03537	#define RMDIR             40
 03538	#define DUP               41 
 03539	#define PIPE              42 
 03540	#define TIMES             43
 03541	#define SETGID            46
 03542	#define GETGID            47
 03543	#define SIGNAL            48
 03544	#define IOCTL             54
 03545	#define FCNTL             55
 03546	#define EXEC              59
 03547	#define UMASK             60 
 03548	#define CHROOT            61 
 03549	#define SETSID            62
 03550	#define GETPGRP           63
 03551	
 03552	/* Следующие определения не являются системными вызовами, но обрабатываются подобно им. */
 03553	#define UNPAUSE           65    /* Менеджеру процессов или файловой системе: проверка EINTR */
 03554	#define REVIVE            67    /* Файловой системе: разбудить спящий процесс */
 03555	#define TASK_REPLY        68    /* Файловой системе: ответный код задания терминала */
 03556	
 03557	/* Обработка сигналов по стандарту Posix. */
 03558	#define SIGACTION         71
 03559	#define SIGSUSPEND        72
 03560	#define SIGPENDING        73
 03561	#define SIGPROCMASK       74
 03562	#define SIGRETURN         75
 03563	
 03564	#define REBOOT            76    /* менеджеру процессов */
 03565	
 03566	/* Специфичные вызовы MINIX, например, для поддержки системных служб. */
 03567	#define SVRCTL            77
 03568	                                /* не используется */
 03569	#define GETSYSINFO        79    /* менеджеру процессов или файловой системе */
 03570	#define GETPROCNR         80    /* менеджеру процессов */
 03571	#define DEVCTL            81    /* файловой системе */
 03572	#define FSTATFS           82    /* файловой системе */
 03573	#define ALLOCMEM          83    /* менеджеру процессов */
 03574	#define FREEMEM           84    /* менеджеру процессов */
 03575	#define SELECT            85    /* файловой системе */
 03576	#define FCHDIR            86    /* файловой системе */
 03577	#define FSYNC             87    /* файловой системе */
 03578	#define GETPRIORITY       88    /* менеджеру процессов */
 03579	#define SETPRIORITY       89    /* менеджеру процессов */
 03580	#define GETTIMEOFDAY      90    /* менеджеру процессов */





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/minix/com.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 03600	#ifndef _MINIX_COM_H
 03601	#define _MINIX_COM_H 
 03602	
 03603	/*===========================================================================*
 03604	 *                            Магические числа процессов                      *
 03605	 *===========================================================================*/
 03606	
 03607	#define ANY             0x7ace  /* обозначает 'любой процесс' */
 03608	#define NONE            0x6ace  /* обозначает 'ни один процесс' */
 03609	#define SELF            0x8ace  /* обозначает 'сам процесс' */
 03610	
 03611	/*===========================================================================*
 03612	 *                     Номера процессов в образе системы                     *
 03613	 *===========================================================================*/
 03614	
 03615	/* Значения некоторых номеров заданий зависят от того, включены ли эти или другие
 03616	 * задания. В общем они определены как PREVIOUS_TASK - ENABLE_TASK. ENABLE_TASK
 03617	 * принимает значение 0 или 1, поэтому задание либо получает новый номер, либо
 03618	 * тот же номер, что и предыдущее задание, и далее не используется. Обратите внимание,
 03619	 * что порядок должен соответствовать таблице заданий, определенной в table.c. 
 03620	 */
 03621	
 03622	/* Задания ядра, выполняемые в едином адресном пространстве. */
 03623	#define IDLE             -4     /* выполняется, когда ни один из процессов не может быть выполнен */
 03624	#define CLOCK            -3     /* таймеры и другие функции часов */
 03625	#define SYSTEM           -2     /* запрос функций системы */
 03626	#define KERNEL           -1     /* псевдопроцесс для IPC и планирования */
 03627	#define HARDWARE     KERNEL     /* для обработчиков аппаратных прерываний */
 03628	
 03629	/* Число заданий. Определение NR_PROCS находится в <minix/config.h>. */
 03630	#define NR_TASKS          4 
 03631	
 03632	/* Процессы пространства пользователя - драйверы устройств, серверы и INIT. */
 03633	#define PM_PROC_NR        0     /* менеджер процессов */
 03634	#define FS_PROC_NR        1     /* файловая система */
 03635	#define RS_PROC_NR        2     /* сервер реинкарнации */
 03636	#define MEM_PROC_NR       3     /* драйвер памяти (виртуальный диск, null и т. д.) */
 03637	#define LOG_PROC_NR       4     /* драйвер журнала */
 03638	#define TTY_PROC_NR       5     /* драйвер терминала (TTY) */
 03639	#define DRVR_PROC_NR      6     /* драйвер устройства для загрузочного носителя */
 03640	#define INIT_PROC_NR      7     /* init */
 03641	
 03642	/* Число процессов, содержащихся в образе системы. */
 03643	#define NR_BOOT_PROCS   (NR_TASKS + INIT_PROC_NR + 1)
 03644	
 03645	/*===========================================================================*
 03646	 *                           Типы уведомлений ядра                           *
 03647	 *===========================================================================*/
 03648	
 03649	/* Типы уведомлений ядра. Уведомления можно передавать любому процессу, поэтому необходимо
 03650	 * гарантировать, что их тип отличается от других типов сообщений. Уведомления 
 03651	 * приоритезованы по разблокированию и доставке уведомлений о блокировке. 
 03652	 * Чем меньше число, тем выше приоритет. Смещения
 03653	 * используются для битовых карт уведомлений, имеющихся у каждого процесса.
 03654	 */
 03655	#define NOTIFY_MESSAGE            0x1000
 03656	#define NOTIFY_FROM(p_nr)        (NOTIFY_MESSAGE | ((p_nr) + NR_TASKS)) 
 03657	#  define SYN_ALARM     NOTIFY_FROM(CLOCK)      /* синхронный таймер */
 03658	#  define SYS_SIG       NOTIFY_FROM(SYSTEM)     /* системный сигнал */
 03659	#  define HARD_INT      NOTIFY_FROM(HARDWARE)   /* аппаратное прерывание */
 03660	#  define NEW_KSIG      NOTIFY_FROM(HARDWARE)   /* новый сигнал ядра */
 03661	#  define FKEY_PRESSED  NOTIFY_FROM(TTY_PROC_NR)/* нажатие функциональной клавиши */
 03662	
 03663	/* Интерфейс для параметров сообщений, передаваемых с уведомлениями. */
 03664	#define NOTIFY_SOURCE           m_source
 03665	#define NOTIFY_TYPE             m_type
 03666	#define NOTIFY_ARG              m2_l1
 03667	#define NOTIFY_TIMESTAMP        m2_l2
 03668	#define NOTIFY_FLAGS            m2_i1
 03669	
 03670	/*===========================================================================*
 03671	 *          Сообщения для драйверов блочных и символьных устройств           *
 03672	 *===========================================================================*/
 03673	
 03674	/* Типы сообщений для драйверов устройств. */
 03675	#define DEV_RQ_BASE   0x400     /* база для типов запросов к устройствам */
 03676	#define DEV_RS_BASE   0x500     /* база для типов ответов устройств */
 03677	
 03678	#define CANCEL          (DEV_RQ_BASE +  0) /* общий запрос на завершение задания */
 03679	#define DEV_READ        (DEV_RQ_BASE +  3) /* чтение из вспомогательного устройства */
 03680	#define DEV_WRITE       (DEV_RQ_BASE +  4) /* запись во вспомогательное устройство */
 03681	#define DEV_IOCTL       (DEV_RQ_BASE +  5) /* код управления вводом-вывыдом */
 03682	#define DEV_OPEN        (DEV_RQ_BASE +  6) /* открыть вспомогательное устройство */
 03683	#define DEV_CLOSE       (DEV_RQ_BASE +  7) /* закрыть вспомогательное устройство */
 03684	#define DEV_SCATTER     (DEV_RQ_BASE +  8) /* запись из вектора */
 03685	#define DEV_GATHER      (DEV_RQ_BASE +  9) /* чтение в вектор */
 03686	#define TTY_SETPGRP     (DEV_RQ_BASE + 10) /* установка группы процесса */
 03687	#define TTY_EXIT        (DEV_RQ_BASE + 11) /* лидер группы завершил работу */    
 03688	#define DEV_SELECT      (DEV_RQ_BASE + 12) /* запрос обработки функцией select() */
 03689	#define DEV_STATUS      (DEV_RQ_BASE + 13) /* запрос состояния драйвера */
 03690	
 03691	#define DEV_REPLY       (DEV_RS_BASE + 0) /* общий ответ задания */
 03692	#define DEV_CLONED      (DEV_RS_BASE + 1) /* возврат клонированного вспомогательного устройства */
 03693	#define DEV_REVIVE      (DEV_RS_BASE + 2) /* драйвер "оживляет" процесс */
 03694	#define DEV_IO_READY    (DEV_RS_BASE + 3) /* выбранное устройство готово */
 03695	#define DEV_NO_STATUS   (DEV_RS_BASE + 4) /* пустой ответ о состоянии */
 03696	
 03697	/* Имена полей для сообщений, адресованных драйвером блочных и символьных устройств */
 03698	#define DEVICE          m2_i1   /* главное/вспомогательное устройство */
 03699	#define PROC_NR         m2_i2   /* какой процесс хочет выполнить ввод-вывод? */
 03700	#define COUNT           m2_i3   /* сколько байтов передать */
 03701	#define REQUEST         m2_i3   /* код запроса ioctl */
 03702	#define POSITION        m2_l1   /* файловое смещение */
 03703	#define ADDRESS         m2_p1   /* адрес буфера */
 03704	
 03705	/* Имена полей для сообщений DEV_SELECT, адресуемых драйверам устройств. */
 03706	#define DEV_MINOR       m2_i1   /* вспомогательное устройство */
 03707	#define DEV_SEL_OPS     m2_i2   /* какие операции select затребованы */
 03708	#define DEV_SEL_WATCH   m2_i3   /* уведомление, если нет готовых операций */
 03709	
 03710	/* Имена полей, используемые в ответных сообщениях заданий. */
 03711	#define REP_PROC_NR     m2_i1   /* число процессов, от имени которых был осуществлен ввод-вывод */
 03712	#define REP_STATUS      m2_i2   /* число переданных байтов или номер ошибки */
 03713	#  define SUSPEND        -998   /* состояние – вызывающий процесс должен ждать, ответ отложен */
 03714	
 03715	/* Имена полей для сообщений драйверу терминала. */
 03716	#define TTY_LINE        DEVICE  /* параметр сообщения:  линия терминала */
 03717	#define TTY_REQUEST     COUNT   /* параметр сообщения:  код запроса ioctl */
 03718	#define TTY_SPEK        POSITION/* параметр сообщения:  скорость ioctl при стирании */
 03719	#define TTY_FLAGS       m2_l2   /* параметр сообщения:  режим терминала ioctl */
 03720	#define TTY_PGRP        m2_i3   /* параметр сообщения:  группа процесса */  
 03721	
 03722	/* Имена полей для ответа о состоянии QIC 02 от драйвера ленточного накопителя */
 03723	#define TAPE_STAT0      m2_l1
 03724	#define TAPE_STAT1      m2_l2
 03725	
 03726	/*===========================================================================*
 03727	 *                         Сообщения для сетевого уровня                     *
 03728	 *===========================================================================*/
 03729	
 03730	/* Типы сообщений для запросов сетевого уровня. Сетевой уровень работает подобно драйверу. */
 03731	#define NW_OPEN         DEV_OPEN
 03732	#define NW_CLOSE        DEV_CLOSE
 03733	#define NW_READ         DEV_READ
 03734	#define NW_WRITE        DEV_WRITE
 03735	#define NW_IOCTL        DEV_IOCTL
 03736	#define NW_CANCEL       CANCEL
 03737	
 03738	/* Базовый тип для запросов и ответов канального уровня. */
 03739	#define DL_RQ_BASE      0x800           
 03740	#define DL_RS_BASE      0x900           
 03741	
 03742	/* Типы сообщений для запросов канального уровня. */
 03743	#define DL_WRITE        (DL_RQ_BASE + 3)
 03744	#define DL_WRITEV       (DL_RQ_BASE + 4)
 03745	#define DL_READ         (DL_RQ_BASE + 5)
 03746	#define DL_READV        (DL_RQ_BASE + 6)
 03747	#define DL_INIT         (DL_RQ_BASE + 7)
 03748	#define DL_STOP         (DL_RQ_BASE + 8)
 03749	#define DL_GETSTAT      (DL_RQ_BASE + 9)
 03750	
 03751	/* Типы сообщений для ответов канального уровня. */
 03752	#define DL_INIT_REPLY   (DL_RS_BASE + 20)
 03753	#define DL_TASK_REPLY   (DL_RS_BASE + 21)
 03754	
 03755	/* Имена полей для сообщений канального уровня. */
 03756	#define DL_PORT         m2_i1
 03757	#define DL_PROC         m2_i2
 03758	#define DL_COUNT        m2_i3
 03759	#define DL_MODE         m2_l1
 03760	#define DL_CLCK         m2_l2
 03761	#define DL_ADDR         m2_p1
 03762	#define DL_STAT         m2_l1
 03763	
 03764	/* Биты поля DL_STAT ответов DL. */
 03765	#  define DL_PACK_SEND          0x01
 03766	#  define DL_PACK_RECV          0x02
 03767	#  define DL_READ_IP            0x04
 03768	
 03769	/* Биты поля DL_MODE запросов DL. */
 03770	#  define DL_NOMODE             0x0
 03771	#  define DL_PROMISC_REQ        0x2
 03772	#  define DL_MULTI_REQ          0x4
 03773	#  define DL_BROAD_REQ          0x8
 03774	
 03775	/*===========================================================================*
 03776	 *                 Типы запросов и имена полей системного задания            *
 03777	 *===========================================================================*/
 03778	
 03779	/* Вызовы системной библиотеки передаются в виде вектора вызовов. По этой причине необходимо 
 03780	 * соблюдать осторожность при изменении номеров системных вызовов. Номера, заданные
 03781	 * здесь, определяют, какой вызов совершается из вектора.
 03782	 */ 
 03783	#define KERNEL_CALL     0x600   /* база для вызовов ядра, адресованных процессу SYSTEM */ 
 03784	
 03785	#  define SYS_FORK       (KERNEL_CALL + 0)      /* sys_fork() */
 03786	#  define SYS_EXEC       (KERNEL_CALL + 1)      /* sys_exec() */
 03787	#  define SYS_EXIT       (KERNEL_CALL + 2)      /* sys_exit() */
 03788	#  define SYS_NICE       (KERNEL_CALL + 3)      /* sys_nice() */
 03789	#  define SYS_PRIVCTL    (KERNEL_CALL + 4)      /* sys_privctl() */
 03790	#  define SYS_TRACE      (KERNEL_CALL + 5)      /* sys_trace() */
 03791	#  define SYS_KILL       (KERNEL_CALL + 6)      /* sys_kill() */
 03792	
 03793	#  define SYS_GETKSIG    (KERNEL_CALL + 7)      /* sys_getsig() */
 03794	#  define SYS_ENDKSIG    (KERNEL_CALL + 8)      /* sys_endsig() */
 03795	#  define SYS_SIGSEND    (KERNEL_CALL + 9)      /* sys_sigsend() */
 03796	#  define SYS_SIGRETURN  (KERNEL_CALL + 10)     /* sys_sigreturn() */
 03797	
 03798	#  define SYS_NEWMAP     (KERNEL_CALL + 11)     /* sys_newmap() */
 03799	#  define SYS_SEGCTL     (KERNEL_CALL + 12)     /* sys_segctl() */
 03800	#  define SYS_MEMSET     (KERNEL_CALL + 13)     /* sys_memset() */
 03801	
 03802	#  define SYS_UMAP       (KERNEL_CALL + 14)     /* sys_umap() */
 03803	#  define SYS_VIRCOPY    (KERNEL_CALL + 15)     /* sys_vircopy() */
 03804	#  define SYS_PHYSCOPY   (KERNEL_CALL + 16)     /* sys_physcopy() */
 03805	#  define SYS_VIRVCOPY   (KERNEL_CALL + 17)     /* sys_virvcopy() */
 03806	#  define SYS_PHYSVCOPY  (KERNEL_CALL + 18)     /* sys_physvcopy() */
 03807	
 03808	#  define SYS_IRQCTL     (KERNEL_CALL + 19)     /* sys_irqctl() */
 03809	#  define SYS_INT86      (KERNEL_CALL + 20)     /* sys_int86() */
 03810	#  define SYS_DEVIO      (KERNEL_CALL + 21)     /* sys_devio() */
 03811	#  define SYS_SDEVIO     (KERNEL_CALL + 22)     /* sys_sdevio() */
 03812	#  define SYS_VDEVIO     (KERNEL_CALL + 23)     /* sys_vdevio() */
 03813	
 03814	#  define SYS_SETALARM   (KERNEL_CALL + 24)     /* sys_setalarm() */
 03815	#  define SYS_TIMES      (KERNEL_CALL + 25)     /* sys_times() */
 03816	#  define SYS_GETINFO    (KERNEL_CALL + 26)     /* sys_getinfo() */
 03817	#  define SYS_ABORT      (KERNEL_CALL + 27)     /* sys_abort() */
 03818	
 03819	#define NR_SYS_CALLS    28      /* число системных вызовов */ 
 03820	
 03821	/* Имена полей для SYS_MEMSET и SYS_SEGCTL. */
 03822	#define MEM_PTR         m2_p1   /* база */
 03823	#define MEM_COUNT       m2_l1   /* счетчик */
 03824	#define MEM_PATTERN     m2_l2   /* записываемый образ */
 03825	#define MEM_CHUNK_BASE  m4_l1   /* физический базовый адрес */
 03826	#define MEM_CHUNK_SIZE  m4_l2   /* размер единицы памяти */
 03827	#define MEM_TOT_SIZE    m4_l3   /* общий размер памяти */
 03828	#define MEM_CHUNK_TAG   m4_l4   /* признак, идентифицирующий единицу памяти */
 03829	
 03830	/* Имена полей для SYS_DEVIO, SYS_VDEVIO и SYS_SDEVIO. */
 03831	#define DIO_REQUEST     m2_i3   /* входное/выходное устройство */
 03832	#   define DIO_INPUT        0   /* вход */
 03833	#   define DIO_OUTPUT       1   /* выход */
 03834	#define DIO_TYPE        m2_i1   /* флаг, индицирующий байт, слово или тип long */ 
 03835	#   define DIO_BYTE       'b'   /* значения типа байт */
 03836	#   define DIO_WORD       'w'   /* значения типа слово */
 03837	#   define DIO_LONG       'l'   /* значения типа long */
 03838	#define DIO_PORT        m2_l1   /* адрес порта */
 03839	#define DIO_VALUE       m2_l2   /* вводимое/выводимое значение */
 03840	#define DIO_VEC_ADDR    m2_p1   /* адрес буфера или пары (порт, вектор) */
 03841	#define DIO_VEC_SIZE    m2_l2   /* число элементов в векторе */
 03842	#define DIO_VEC_PROC    m2_i2   /* номер процесса вектора */
 03843	
 03844	/* Имена полей для SYS_SIGNARLM, SYS_FLAGARLM и SYS_SYNCALRM. */
 03845	#define ALRM_EXP_TIME   m2_l1   /* время истечения таймера */
 03846	#define ALRM_ABS_TIME   m2_i2   /* установить в 1 для использования абсолютного времени истечения таймера */
 03847	#define ALRM_TIME_LEFT  m2_l1   /* число оставшихся тактов */
 03848	#define ALRM_PROC_NR    m2_i1   /* процесс, установивший таймер */
 03849	#define ALRM_FLAG_PTR   m2_p1   /* виртуальный адрес флага истечения таймера */   
 03850	
 03851	/* Имена полей для SYS_IRQCTL. */
 03852	#define IRQ_REQUEST     m5_c1   /* что делать */
 03853	#  define IRQ_SETPOLICY     1   /* управление записью таблицы IRQ */
 03854	#  define IRQ_RMPOLICY      2   /* удаление записи из таблицы IRQ */
 03855	#  define IRQ_ENABLE        3   /* разрешение прерываний */
 03856	#  define IRQ_DISABLE       4   /* запрещение прерываний */
 03857	#define IRQ_VECTOR      m5_c2   /* вектор прерывания */
 03858	#define IRQ_POLICY      m5_i1   /* параметры для запроса IRQCTL */
 03859	#  define IRQ_REENABLE  0x001   /* заново включить линию прерывания после прерывания */
 03860	#  define IRQ_BYTE      0x100   /* значения типа байт */
 03861	#  define IRQ_WORD      0x200   /* значения типа слово */
 03862	#  define IRQ_LONG      0x400   /* значения типа long */
 03863	#define IRQ_PROC_NR     m5_i2   /* номер процесса, SELF, NONE */
 03864	#define IRQ_HOOK_ID     m5_l3   /* идентификатор обработчика прерывания в ядре */
 03865	
 03866	/* Имена полей для SYS_SEGCTL. */
 03867	#define SEG_SELECT      m4_l1   /* возвращаемый селектор сегмента */ 
 03868	#define SEG_OFFSET      m4_l2   /* возвращаемое смещение в сегменте */
 03869	#define SEG_PHYS        m4_l3   /* физический адрес сегмента */
 03870	#define SEG_SIZE        m4_l4   /* размер сегмента */
 03871	#define SEG_INDEX       m4_l5   /* индекс сегмента в удаленной карте */
 03872	
 03873	/* Имена полей для SYS_VIDCOPY. */
 03874	#define VID_REQUEST     m4_l1   /* что делать */
 03875	#  define VID_VID_COPY     1    /* запрос vid_vid_copy() */
 03876	#  define MEM_VID_COPY     2    /* запрос mem_vid_copy() */
 03877	#define VID_SRC_ADDR    m4_l2   /* виртуальный адрес в памяти */
 03878	#define VID_SRC_OFFSET  m4_l3   /* смещение в видеопамяти */
 03879	#define VID_DST_OFFSET  m4_l4   /* смещение в видеопамяти */
 03880	#define VID_CP_COUNT    m4_l5   /* число копируемых слов */
 03881	
 03882	/* Имена полей для SYS_ABORT. */
 03883	#define ABRT_HOW        m1_i1   /* RBT_REBOOT, RBT_HALT и т. Д. */
 03884	#define ABRT_MON_PROC   m1_i2   /* процесс, содержащий параметры монитора */
 03885	#define ABRT_MON_LEN    m1_i3   /* длина параметров монитора */
 03886	#define ABRT_MON_ADDR   m1_p1   /* виртуальный адрес параметров монитора */
 03887	
 03888	/* Имена полей для _UMAP, _VIRCOPY и _PHYSCOPY. */
 03889	#define CP_SRC_SPACE    m5_c1   /* пространство (T или D, стеку соответствует D) */
 03890	#define CP_SRC_PROC_NR  m5_i1   /* процесс, из которого осуществляется копирование */
 03891	#define CP_SRC_ADDR     m5_l1   /* адрес копируемых данных */
 03892	#define CP_DST_SPACE    m5_c2   /* пространство (T или D, стеку соответствует D) */
 03893	#define CP_DST_PROC_NR  m5_i2   /* процесс, в который осуществляется копирование */
 03894	#define CP_DST_ADDR     m5_l2   /* адрес, в который копируются данные */
 03895	#define CP_NR_BYTES     m5_l3   /* число копируемых байтов */
 03896	
 03897	/* Имена полей для SYS_VCOPY и SYS_VVIRCOPY. */
 03898	#define VCP_NR_OK       m1_i2   /* число успешных операций копирования */
 03899	#define VCP_VEC_SIZE    m1_i3   /* размер вектора копирования */
 03900	#define VCP_VEC_ADDR    m1_p1   /* указатель на вектор копирования */
 03901	
 03902	/* Имена полей для SYS_GETINFO. */
 03903	#define I_REQUEST      m7_i3    /* какую информацию получить */
 03904	#   define GET_KINFO       0    /* получить информационную структуру ядра */
 03905	#   define GET_IMAGE       1    /* получить таблицу системного образа */
 03906	#   define GET_PROCTAB     2    /* получить таблицу процессов ядра */
 03907	#   define GET_RANDOMNESS  3    /* получить буфер случайных чисел */
 03908	#   define GET_MONPARAMS   4    /* получить параметры монитора */
 03909	#   define GET_KENV        5    /* получить строку окружения ядра */
 03910	#   define GET_IRQHOOKS    6    /* получить таблицу IRQ */
 03911	#   define GET_KMESSAGES   7    /* получить сообщения ядра */
 03912	#   define GET_PRIVTAB     8    /* получить таблицу привилегий ядра */
 03913	#   define GET_KADDRESSES  9    /* получить различные адреса ядра */
 03914	#   define GET_SCHEDINFO  10    /* получить очереди планирования */
 03915	#   define GET_PROC       11    /* получить запись определенного процесса */
 03916	#   define GET_MACHINE    12    /* получить информацию о компьютере */
 03917	#   define GET_LOCKTIMING 13    /* получить величину задержки lock()/unlock() */
 03918	#   define GET_BIOSBUFFER 14    /* получить буфер для вызовов BIOS */
 03919	#define I_PROC_NR      m7_i4    /* вызывающий процесс */
 03920	#define I_VAL_PTR      m7_p1    /* виртуальный адрес в вызывающем процессе */ 
 03921	#define I_VAL_LEN      m7_i1    /* максимальный размер значения */
 03922	#define I_VAL_PTR2     m7_p2    /* второй виртуальный адрес */ 
 03923	#define I_VAL_LEN2     m7_i2    /* второй размер или номер процесса */
 03924	
 03925	/* Имена полей для SYS_TIMES. */
 03926	#define T_PROC_NR      m4_l1    /* процесс, для которого следует запросить информацию о времени */
 03927	#define T_USER_TIME    m4_l1    /* время пользователя, затраченное процессом */
 03928	#define T_SYSTEM_TIME  m4_l2    /* системное время, затраченное пользователем */
 03929	#define T_CHILD_UTIME  m4_l3    /* время пользователя, затраченное потомками процесса */
 03930	#define T_CHILD_STIME  m4_l4    /* системное время, затраченное потомками процесса */
 03931	#define T_BOOT_TICKS   m4_l5    /* число тактов с момента последней загрузки системы */
 03932	
 03933	/* Имена полей для SYS_TRACE и SYS_SVRCTL. */
 03934	#define CTL_PROC_NR    m2_i1    /* номер вызывающего процесса */
 03935	#define CTL_REQUEST    m2_i2    /* запрос управления сервером */
 03936	#define CTL_MM_PRIV    m2_i3    /* привилегии, видимые менеджером процессов */
 03937	#define CTL_ARG_PTR    m2_p1    /* указатель на аргумент */
 03938	#define CTL_ADDRESS    m2_l1    /* адрес в пространстве трассируемого процесса */
 03939	#define CTL_DATA       m2_l2    /* поле данных для трассировки */
 03940	
 03941	/* Имена полей для SYS_KILL и SYS_SIGCTL */
 03942	#define SIG_REQUEST    m2_l2    /* запрос контроля сигнала менеджера процессов */
 03943	#define S_GETSIG           0    /* получить активный сигнал ядра */
 03944	#define S_ENDSIG           1    /* завершить сигнал ядра */
 03945	#define S_SENDSIG          2    /* обработка сигналов в стиле POSIX */
 03946	#define S_SIGRETURN        3    /* возврат из обработки POSIX */
 03947	#define S_KILL             4    /* сервер уничтожает процесс сигналом */
 03948	#define SIG_PROC       m2_i1    /* номер процесса */
 03949	#define SIG_NUMBER     m2_i2    /* номер сигнала */
 03950	#define SIG_FLAGS      m2_i3    /* поле флагов сигнала */
 03951	#define SIG_MAP        m2_l1    /* используется ядром для передачи битовой карты сигналов */
 03952	#define SIG_CTXT_PTR   m2_p1    /* указатель на информацию, восстанавливающую контекст сигналов */
 03953	
 03954	/* Имена полей для SYS_FORK, _EXEC, _EXIT и _NEWMAP. */
 03955	#define PR_PROC_NR     m1_i1    /* указывает дочерний процесс */
 03956	#define PR_PRIORITY    m1_i2    /* приоритет процесса */
 03957	#define PR_PPROC_NR    m1_i2    /* указывает родительский процесс */
 03958	#define PR_PID         m1_i3    /* идентификатор процесса в менеджере процессов */
 03959	#define PR_STACK_PTR   m1_p1    /* используется как указатель стека в sys_exec и sys_getsp */
 03960	#define PR_TRACING     m1_i3    /* флаг, указывающий включение или отключение трассировки */
 03961	#define PR_NAME_PTR    m1_p2    /* указывает dmp, где находится имя программы для dmp */
 03962	#define PR_IP_PTR      m1_p3    /* начальное значение ip после exec */
 03963	#define PR_MEM_PTR     m1_p1    /* указывает sys_newmap, где находится карта памяти */
 03964	
 03965	/* Имена полей для SYS_INT86 */
 03966	#define INT86_REG86    m1_p1    /* указатель на регистры */
 03967	
 03968	/* Имена полей для SELECT (FS). */
 03969	#define SEL_NFDS       m8_i1
 03970	#define SEL_READFDS    m8_p1
 03971	#define SEL_WRITEFDS   m8_p2
 03972	#define SEL_ERRORFDS   m8_p3
 03973	#define SEL_TIMEOUT    m8_p4
 03974	
 03975	/*===========================================================================*
 03976	 *                Сообщения серверу управления системой                      *
 03977	 *===========================================================================*/
 03978	
 03979	#define SRV_RQ_BASE             0x700
 03980	
 03981	#define SRV_UP          (SRV_RQ_BASE + 0)       /* запустить системную службу */
 03982	#define SRV_DOWN        (SRV_RQ_BASE + 1)       /* остановить системную службу */
 03983	#define SRV_STATUS      (SRV_RQ_BASE + 2)       /* получить состояние службы */
 03984	
 03985	#  define SRV_PATH_ADDR         m1_p1           /* путь к двоичному файлу */
 03986	#  define SRV_PATH_LEN          m1_i1           /* длина двоичного файла */
 03987	#  define SRV_ARGS_ADDR         m1_p2           /* передаваемые аргументы */
 03988	#  define SRV_ARGS_LEN          m1_i2           /* длина аргументов */
 03989	#  define SRV_DEV_MAJOR         m1_i3           /* номер главного устройства */
 03990	#  define SRV_PRIV_ADDR         m1_p3           /* строка привилегий */
 03991	#  define SRV_PRIV_LEN          m1_i3           /* длина привилегий */
 03992	
 03993	/*===========================================================================*
 03994	 *             Различные сообщения, используемые терминалом                  *
 03995	 *===========================================================================*/
 03996	
 03997	/* Различные типы запросов и имена полей, например, используемые информационным сервером */
 03998	#define PANIC_DUMPS             97      /* отладочные дампы терминала при RBT_PANIC */
 03999	#define FKEY_CONTROL            98      /* функциональная клавиша терминала */
 04000	#  define FKEY_REQUEST       m2_i1      /* запрос для выполнения на терминале */
 04001	#  define    FKEY_MAP           10      /* наблюдение функциональной клавиши */
 04002	#  define    FKEY_UNMAP         11      /* завершить отслеживание функциональной клавиши */
 04003	#  define    FKEY_EVENTS        12      /* наблюдение сочетаний клавиш */
 04004	#  define FKEY_FKEYS          m2_l1     /* нажаты клавиши F1-F12 */
 04005	#  define FKEY_SFKEYS         m2_l2     /* нажаты клавиши Shift-F1-F12 */
 04006	#define DIAGNOSTICS     100     /* вывод строки в обход файловой системы */
 04007	#  define DIAG_PRINT_BUF      m1_p1
 04008	#  define DIAG_BUF_COUNT      m1_i1
 04009	#  define DIAG_PROC_NR        m1_i2
 04010	
 04011	#endif /* _MINIX_COM_H */ 




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/minix/devio.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 04100	/* Этот файл содержит базовые типы и константы для системных вызовов 
 04101	 * SYS_DEVIO и SYS_VDEVIO, позволяющих процессам уровня пользователя 
 04102	 * осуществлять ввод (вывод) с (на) устройства. 
 04103	 *
 04104	 * Создан:  
 04105	 *      08 апреля 2004, Jorrit N. Herder
 04106	 */
 04107	
 04108	#ifndef _DEVIO_H
 04109	#define _DEVIO_H
 04110	
 04111	#include <minix/sys_config.h>     /* необходимо включить <minix/type.h> */
 04112	#include <sys/types.h>        /* необходимы типы u8_t, u16_t, u32_t */
 04113	
 04114	typedef u16_t port_t;
 04115	typedef U16_t Port_t;
 04116	
 04117	/* Возможны различные разрядности портов ввода-вывода:  8, 16 и 32 бита.
 04118	 * Также см. файл <ibm/portio.h>, содержащий функции для байтов, слов и данных 
 04119	 * типа long. Таким образом, нам нужны различные типы пар (порт, значение). 
 04120	 */
 04121	typedef struct { u16_t port;  u8_t value; } pvb_pair_t;
 04122	typedef struct { u16_t port; u16_t value; } pvw_pair_t;
 04123	typedef struct { u16_t port; u32_t value; } pvl_pair_t;
 04124	
 04125	/* Макро-интерфейс для задания пары (порт, значение). */
 04126	#define pv_set(pv, p, v) ((pv).port = (p), (pv).value = (v))
 04127	#define pv_ptr_set(pv_ptr, p, v) ((pv_ptr)->port = (p), (pv_ptr)->value = (v))
 04128	
 04129	#endif  /* _DEVIO_H */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/minix/dmap.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 04200	#ifndef _DMAP_H
 04201	#define _DMAP_H
 04202	
 04203	#include <minix/sys_config.h>
 04204	#include <minix/ipc.h>
 04205	
 04206	/*===========================================================================*
 04207	 *                 Таблица соответствия устройств и драйверов                *
 04208	 *===========================================================================*/
 04209	
 04210	/* Таблица устройств, индексируемая по номерам главных устройств. Она определяет
 04211	 * соответствие между номерами главных устройств и процедурами, обслуживающими их.
 04212	 * Таблица может динамически обновляться. Поле dmap_flags описывает текущее состояние
 04213	 * записи и определяет возможные параметры управления. 
 04214	 */
 04215	#define DMAP_MUTABLE            0x01    /* назначения могут быть изменены */
 04216	#define DMAP_BUSY               0x02    /* драйвер занят обработкой запроса */
 04217	
 04218	enum dev_style { STYLE_DEV, STYLE_NDEV, STYLE_TTY, STYLE_CLONE };
 04219	
 04220	extern struct dmap {
 04221	  int _PROTOTYPE ((*dmap_opcl), (int, Dev_t, int, int) );
 04222	  void _PROTOTYPE ((*dmap_io), (int, message *) );
 04223	  int dmap_driver;
 04224	  int dmap_flags;
 04225	} dmap[];
 04226	
 04227	/*===========================================================================*
 04228	 *                Номера главных и вспомогательных устройств                  *
 04229	 *===========================================================================*/
 04230	
 04231	/* Общее число различных устройств. */
 04232	#define NR_DEVICES                32                    /* число главных устройств */
 04233	
 04234	/* Номера главных и вспомогательных устройств для драйвера памяти. */
 04235	#define MEMORY_MAJOR               1    /* главный номер устройств памяти */
 04236	#  define RAM_DEV                  0    /* вспомогательный номер /dev/ram */
 04237	#  define MEM_DEV                  1    /* вспомогательный номер /dev/mem */
 04238	#  define KMEM_DEV                 2    /* вспомогательный номер /dev/kmem */
 04239	#  define NULL_DEV                 3    /* вспомогательный номер /dev/null */
 04240	#  define BOOT_DEV                 4    /* вспомогательный номер /dev/boot */
 04241	#  define ZERO_DEV                 5    /* вспомогательный номер /dev/zero */
 04242	
 04243	#define CTRLR(n) ((n)==0 ? 3 :  (8 + 2*((n)-1))) /* магическая формула */
 04244	
 04245	/* Номера устройств, особенные для монитора загрузки и файловой системы. */
 04246	#  define DEV_RAM             0x0100    /* номер устройства /dev/ram */
 04247	#  define DEV_BOOT            0x0104    /* номер устройства /dev/boot */
 04248	
 04249	#define FLOPPY_MAJOR               2    /* главный номер накопителя гибких дисков */
 04250	#define TTY_MAJOR                  4    /* главный номер терминалов */
 04251	#define CTTY_MAJOR                 5    /* главный номер for /dev/tty */
 04252	
 04253	#define INET_MAJOR                 7    /* главный номер inet */
 04254	
 04255	#define LOG_MAJOR                 15    /* главный номер драйвера журнала */
 04256	#  define IS_KLOG_DEV              0    /* вспомогательный номер /dev/klog */
 04257	
 04258	#endif /* _DMAP_H */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/ibm/portio.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 04300	/*
 04301	ibm/portio.h
 04302	
 04303	Создан:         15 января 1992, Philip Homburg
 04304	*/
 04305	
 04306	#ifndef _PORTIO_H_
 04307	#define _PORTIO_H_
 04308	
 04309	#ifndef _TYPES_H
 04310	#include <sys/types.h>
 04311	#endif
 04312	
 04313	unsigned inb(U16_t _port);
 04314	unsigned inw(U16_t _port);
 04315	unsigned inl(U32_t _port);
 04316	void outb(U16_t _port, U8_t _value);
 04317	void outw(U16_t _port, U16_t _value);
 04318	void outl(U16_t _port, U32_t _value);
 04319	void insb(U16_t _port, void *_buf, size_t _count);
 04320	void insw(U16_t _port, void *_buf, size_t _count);
 04321	void insl(U16_t _port, void *_buf, size_t _count);
 04322	void outsb(U16_t _port, void *_buf, size_t _count);
 04323	void outsw(U16_t _port, void *_buf, size_t _count);
 04324	void outsl(U16_t _port, void *_buf, size_t _count);
 04325	void intr_disable(void);
 04326	void intr_enable(void);
 04327	
 04328	#endif /* _PORTIO_H_ */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/ibm/interrupt.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 04400	/* Номера прерываний и аппаратные векторы. */
 04401	
 04402	#ifndef _INTERRUPT_H
 04403	#define _INTERRUPT_H
 04404	
 04405	#if (CHIP == INTEL)
 04406	
 04407	/* порты контроллера прерываний 8259A. */
 04408	#define INT_CTL         0x20    /* порт ввода-вывода для контроллера прерываний */
 04409	#define INT_CTLMASK     0x21    /* установка бит этого порта запрещает прерывания */
 04410	#define INT2_CTL        0xA0    /* порт ввода-вывода для второго контроллера прерываний */
 04411	#define INT2_CTLMASK    0xA1    /* установка бит этого порта запрещает прерывания */
 04412	
 04413	/* Магические числа для контроллера прерываний. */
 04414	#define END_OF_INT      0x20    /* код, используемый для повторного разрешения прерываний */
 04415	
 04416	/* Векторы прерываний, определенные/зарезервированные процессором. */
 04417	#define DIVIDE_VECTOR      0    /* ошибка деления */
 04418	#define DEBUG_VECTOR       1    /* один шаг (трассировка) */
 04419	#define NMI_VECTOR         2    /* немаскируемое прерывание */
 04420	#define BREAKPOINT_VECTOR  3    /* точка прерывания программы */
 04421	#define OVERFLOW_VECTOR    4    /* от INTO */
 04422	
 04423	/* Фиксированный вектор системных вызовов. */
 04424	#define SYS_VECTOR        32    /* системные вызовы совершаются с прерыванием SYSVEC */
 04425	#define SYS386_VECTOR     33    /* системы, за исключением 386, используют это */
 04426	#define LEVEL0_VECTOR     34    /* для исполнения функции на уровне 0 */
 04427	
 04428	/* Подходящие базы irq для аппаратных прерываний. Перепрограммируйте настройки 8259(s),
 04429	 * совпадающие с настройками PC BIOS по умолчанию, поскольку BIOS не относится ко всем
 04430	 * зарезервированным векторам процессора (0 - 31).
 04431	 */
 04432	#define BIOS_IRQ0_VEC   0x08    /* база векторов IRQ0-7, используемая BIOS */
 04433	#define BIOS_IRQ8_VEC   0x70    /* база векторов IRQ8-15, используемая BIOS  */
 04434	#define IRQ0_VECTOR     0x50    /* векторы, в которые перемещаются IRQ0-7 */
 04435	#define IRQ8_VECTOR     0x70    /* не нужно перемещать IRQ8-15 */
 04436	
 04437	/* Номера аппаратных прерываний. */
 04438	#define NR_IRQ_VECTORS    16
 04439	#define CLOCK_IRQ          0
 04440	#define KEYBOARD_IRQ       1
 04441	#define CASCADE_IRQ        2    /* включение каскадирования второго AT-контроллера */
 04442	#define ETHER_IRQ          3    /* вектор прерываний ethernet по умолчанию */
 04443	#define SECONDARY_IRQ      3    /* вектор прерываний RS232 для порта 2 */
 04444	#define RS232_IRQ          4    /* вектор прерываний RS232 для порта 1 */
 04445	#define XT_WINI_IRQ        5    /* винчестер xt */
 04446	#define FLOPPY_IRQ         6    /* накопитель гибких дисков */
 04447	#define PRINTER_IRQ        7
 04448	#define AT_WINI_0_IRQ     14    /* контроллер 0 винчестера */
 04449	#define AT_WINI_1_IRQ     15    /* контроллер 1 винчестера */
 04450	
 04451	/* Преобразование номера прерывания в аппаратный вектор. */
 04452	#define BIOS_VECTOR(irq)        \
 04453	        (((irq) < 8 ? BIOS_IRQ0_VEC :  BIOS_IRQ8_VEC) + ((irq) & 0x07))
 04454	#define VECTOR(irq)     \
 04455	        (((irq) < 8 ? IRQ0_VECTOR :  IRQ8_VECTOR) + ((irq) & 0x07))
 04456	
 04457	#endif /* (CHIP == INTEL) */
 04458	
 04459	#endif /* _INTERRUPT_H */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      include/ibm/ports.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 04500	/* Адреса и магические числа для различных портов. */
 04501	
 04502	#ifndef _PORTS_H
 04503	#define _PORTS_H
 04504	
 04505	#if (CHIP == INTEL)
 04506	
 04507	/* Различные порты. */
 04508	#define PCR             0x65    /* Плоский регистр управления */
 04509	#define PORT_B          0x61    /* порт ввода-вывода для порта B 8255 (клавиатура, звуковой генератор...) */
 04510	#define TIMER0          0x40    /* порт ввода-вывода для канала 0 таймера */
 04511	#define TIMER2          0x42    /* порт ввода-вывода для канала 2 таймера */
 04512	#define TIMER_MODE      0x43    /* порт ввода-вывода для управления режимом таймера */
 04513	
 04514	#endif /* (CHIP == INTEL) */
 04515	
 04516	#endif /* _PORTS_H */




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/kernel.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 04600	#ifndef KERNEL_H
 04601	#define KERNEL_H
 04602	
 04603	/* Основной заголовочный файл ядра. Он включает некоторые другие файлы и определяет
 04604	 * наиболее важные константы.
 04605	 */
 04606	#define _POSIX_SOURCE      1    /* заголовочные файлы должны включить содержимое, относящееся к POSIX */
 04607	#define _MINIX             1    /* заголовочные файлы должны включить содержимое, относящееся к MINIX */
 04608	#define _SYSTEM            1    /* указание заголовочным файлам на то, что это ядро */
 04609	
 04610	/* Следующие заголовочные файлы включаются в файлы *.c автоматически. */
 04611	#include <minix/config.h>       /* глобальная конфигурация, ДОЛЖНА быть первой */
 04612	#include <ansi.h>               /* стиль C:  ANSI или К&Р, ДОЛЖЕН быть вторым */
 04613	#include <sys/types.h>          /* общие системные типы */
 04614	#include <minix/const.h>        /* специфические константы MINIX */
 04615	#include <minix/type.h>         /* специфические типы MINIX, например, сообщения */
 04616	#include <minix/ipc.h>          /* система реального времени MINIX */
 04617	#include <timers.h>             /* управление сторожевым таймером */
 04618	#include <errno.h>              /* коды возврата и номера ошибок */
 04619	#include <ibm/portio.h>         /* ввод (вывод) с (на) устройства и управление прерываниями */ 
 04620	
 04621	/* Важные заголовочные файлы ядра. */
 04622	#include "config.h"             /* конфигурация, ДОЛЖНА быть первой */
 04623	#include "const.h"              /* константы, ДОЛЖНЫ	 быть вторыми */
 04624	#include "type.h"               /* определения типов, ДОЛЖНЫ быть третьими */
 04625	#include "proto.h"              /* прототипы функций */
 04626	#include "glo.h"                /* глобальные переменные */
 04627	#include "ipc.h"                /* IPC-константы*/
 04628	/* #include "debug.h" */        /* отладка, ДОЛЖНА быть последней среди заголовочных файлов ядра */
 04629	
 04630	#endif /* KERNEL_H */
 04631	




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/config.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 04700	#ifndef CONFIG_H
 04701	#define CONFIG_H
 04702	
 04703	/* Этот файл определяет конфигурацию ядра. Он позволяет устанавливать размеры некоторых
 04704	 * буферов ядра, включать/отключать отладочный код, временнЫе возможности и отдельные  
 04705	 * вызовы ядра.
 04706	 *
 04707	 * Изменения: 
 04708	 *   11 июля 2005       Создан  (Jorrit N. Herder)
 04709	 */
 04710	
 04711	/* Во встраиваемых и сенсорных приложениях некоторые вызовы ядра могут быть ненужными.
 04712	 * В этом разделе вы можете указать, какие вызовы нужны, а какие нет. Код ненужных
 04713	 * вызовов ядра не помещается в системный двоичный файл, что уменьшает его размер. Если
 04714	 * вы не уверены, лучше оставить
 04715	 * все вызовы ядра включенными.
 04716	 */
 04717	#define USE_FORK           1    /* создать новый процесс */
 04718	#define USE_NEWMAP         1    /* установить новую карту памяти */
 04719	#define USE_EXEC           1    /* обновить процесс после исполнения */
 04720	#define USE_EXIT           1    /* выполнить очистку после завершения процесса */
 04721	#define USE_TRACE          1    /* информация о процессе и трассировка */
 04722	#define USE_GETKSIG        1    /* получить активные сигналы ядра */
 04723	#define USE_ENDKSIG        1    /* завершить активные сигналы ядра */
 04724	#define USE_KILL           1    /* послать сигнал процессу */
 04725	#define USE_SIGSEND        1    /* послать сигнал в стиле POSIX */
 04726	#define USE_SIGRETURN      1    /* sys_sigreturn(proc_nr, ctxt_ptr, flags) */
 04727	#define USE_ABORT          1    /* завершить работу MINIX */
 04728	#define USE_GETINFO        1    /* получить копию данных ядра */
 04729	#define USE_TIMES          1    /* получить информацию о времени процесса и системы */
 04730	#define USE_SETALARM       1    /* планирование синхронного сигнала */
 04731	#define USE_DEVIO          1    /* чтение или запись одного порта ввода-вывода */
 04732	#define USE_VDEVIO         1    /* вектор запросов ввода-вывода */
 04733	#define USE_SDEVIO         1    /* выполнить запрос ввода-вывода над буфером */
 04734	#define USE_IRQCTL         1    /* установить политику прерываний */
 04735	#define USE_SEGCTL         1    /* установить удаленный сегмент */
 04736	#define USE_PRIVCTL        1    /* управление системными привилегиями */
 04737	#define USE_NICE           1    /* изменить приоритет планирования */
 04738	#define USE_UMAP           1    /* отображение виртуального адреса в физический */
 04739	#define USE_VIRCOPY        1    /* копирование с использованием виртуальной адресации */ 
 04740	#define USE_VIRVCOPY       1    /* вектор запросов виртуального копирования */
 04741	#define USE_PHYSCOPY       1    /* копирование с использованием физической адресации */
 04742	#define USE_PHYSVCOPY      1    /* вектор запросов физического копирования */
 04743	#define USE_MEMSET         1    /* записать символ в заданную область памяти */
 04744	
 04745	/* Длина имен программ, хранимых в таблице процессов. Она используется только в отладочных
 04746	 * дампах, которые генерирует информационный сервер. Сервер менеджера процессов работает
 04747	 * с собственной копией имени программы.  
 04748	 */
 04749	#define P_NAME_LEN         8
 04750	
 04751	/* Диагностические данные ядра записываются в циклический буфер. После каждого сообщения 
 04752	 * системный сервер получает уведомление, чтобы отобразить сообщение, копию буфера 
 04753	 * можно извлечь. Размеры буферов можно безопасно уменьшить. 
 04754	 */
 04755	#define KMESS_BUF_SIZE   256    
 04756	
 04757	/* Буфер для сбора случайных данных. Он применяется при генерации случайного потока
 04758	 * драйвером памяти в процессе чтения из устройства /dev/random. 
 04759	 */
 04760	#define RANDOM_ELEMENTS   32
 04761	
 04762	/* Данный раздел содержит определения важных системных ресурсов, используемых драйверами
 04763	 * устройств. Число элементов векторов определяется максимумом, необходимым любым взятым
 04764	 * драйвером. Число обработчиков прерываний можно увеличить в системах, где количество
 04765	 * драйверов устройств велико. 
 04766	 */
 04767	#define NR_IRQ_HOOKS      16            /* число обработчиков прерываний */
 04768	#define VDEVIO_BUF_SIZE   64            /* максимальное число элементов в запросе VDEVIO */
 04769	#define VCOPY_VEC_SIZE    16            /* максимальное число элементов в запросе VCOPY */
 04770	
 04771	/* Число байтов в стеке ядра. Пространство выделено в файле mpx.s. */
 04772	#define K_STACK_BYTES   1024    
 04773	
 04774	/* Данный раздел позволяет включить отладку ядра и возможности, связанные с временем.
 04775	 * Для нормального функционирования все параметры должны быть запрещены.
 04776	 */
 04777	#define DEBUG_SCHED_CHECK  0    /* санитарная проверка очередей планирования */
 04778	#define DEBUG_LOCK_CHECK   0    /* санитарная проверка lock() ядра */
 04779	#define DEBUG_TIME_LOCKS   0    /* время, проведенное в блокировке */
 04780	
 04781	#endif /* CONFIG_H */
 04782	



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/const.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 04800	/* Общие макросы и константы, используемые ядром. */
 04801	#ifndef CONST_H
 04802	#define CONST_H
 04803	
 04804	#include <ibm/interrupt.h>      /* номера прерываний и аппаратные векторы */
 04805	#include <ibm/ports.h>          /* адреса портов и магические номера */
 04806	#include <ibm/bios.h>           /* адреса, размеры и магические числа BIOS*/
 04807	#include <ibm/cpu.h>            /* адреса, размеры и магические числа BIOS */
 04808	#include <minix/config.h>
 04809	#include "config.h"
 04810	
 04811	/* Для преобразования адреса в пространстве ядра в физический адрес. Это аналогично 
 04812	 * umap_local(proc_ptr, D, vir, sizeof(*vir)), но менее затратно.
 04813	 */
 04814	#define vir2phys(vir)   (kinfo.data_base + (vir_bytes) (vir))
 04815	
 04816	/* Сопоставление номера процесса идентификатору структуры привилегий. */
 04817	#define s_nr_to_id(n)   (NR_TASKS + (n) + 1)
 04818	
 04819	/* Преобразование указателя на поле структуры в указатель на саму структуру. Он преобразует
 04820	 * &struct_ptr->field' в 'struct_ptr'.
 04821	 */
 04822	#define structof(type, field, ptr) \
 04823	        ((type *) (((char *) (ptr)) - offsetof(type, field)))
 04824	
 04825	/* Константы, используемые в virtual_copy(). Значения должны быть 0 и 1 соответственно. */
 04826	#define _SRC_   0
 04827	#define _DST_   1
 04828	
 04829	/* Число источников случайных данных */
 04830	#define RANDOM_SOURCES  16
 04831	
 04832	/* Константы и макросы для манипуляции битовыми картами. */
 04833	#define BITCHUNK_BITS   (sizeof(bitchunk_t) * CHAR_BIT)
 04834	#define BITMAP_CHUNKS(nr_bits) (((nr_bits)+BITCHUNK_BITS-1)/BITCHUNK_BITS)  
 04835	#define MAP_CHUNK(map,bit) (map)[((bit)/BITCHUNK_BITS)]
 04836	#define CHUNK_OFFSET(bit) ((bit)%BITCHUNK_BITS))
 04837	#define GET_BIT(map,bit) ( MAP_CHUNK(map,bit) & (1 << CHUNK_OFFSET(bit) )
 04838	#define SET_BIT(map,bit) ( MAP_CHUNK(map,bit) |= (1 << CHUNK_OFFSET(bit) )
 04839	#define UNSET_BIT(map,bit) ( MAP_CHUNK(map,bit) &= ~(1 << CHUNK_OFFSET(bit) )
 04840	
 04841	#define get_sys_bit(map,bit) \
 04842	        ( MAP_CHUNK(map.chunk,bit) & (1 << CHUNK_OFFSET(bit) )
 04843	#define set_sys_bit(map,bit) \
 04844	        ( MAP_CHUNK(map.chunk,bit) |= (1 << CHUNK_OFFSET(bit) )
 04845	#define unset_sys_bit(map,bit) \
 04846	        ( MAP_CHUNK(map.chunk,bit) &= ~(1 << CHUNK_OFFSET(bit) )
 04847	#define NR_SYS_CHUNKS   BITMAP_CHUNKS(NR_SYS_PROCS)
 04848	
 04849	/* Слова и маски стека программ. */
 04850	#define INIT_PSW      0x0200    /* Начальное слово состояния */
 04851	#define INIT_TASK_PSW 0x1200    /* Начальное слово состояния для заданий (с IOPL 1) */
 04852	#define TRACEBIT      0x0100    /* для трассировки выполните OR этой маски и слова состояния в proc[] */
 04853	#define SETPSW(rp, new)         /* разрешает установку только определенных битов */ \
 04854	        ((rp)->p_reg.psw = (rp)->p_reg.psw & ~0xCD5 | (new) & 0xCD5)
 04855	#define IF_MASK 0x00000200
 04856	#define IOPL_MASK 0x003000
 04857	
 04858	/* Запретить/разрешить аппаратные прерывания. Параметры lock() и unlock() используются при
 04859	 * включенной отладке. Более подробную информацию вы найдете в файле debug.h.
 04860	 */
 04861	#define lock(c, v)      intr_disable(); 
 04862	#define unlock(c)       intr_enable(); 
 04863	
 04864	/* Размеры таблиц памяти. Загрузочный монитор различает три области памяти,
 04865	 * а именно: ниже 1M, между 1M и 16M, и выше 16M. Для DOS MINIX требуется
 04866	 * больше областей.
 04867	 */
 04868	#define NR_MEMS            8    
 04869	
 04870	#endif /* CONST_H */
 04871	
 04872	
 04873	
 04874	
 04875	





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/type.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 04900	#ifndef TYPE_H
 04901	#define TYPE_H
 04902	
 04903	typedef _PROTOTYPE( void task_t, (void) );
 04904	
 04905	/* Таблица процессов и связанные с ней типы системных свойств. */ 
 04906	typedef int proc_nr_t;                  /* номер записи в таблице процессов */
 04907	typedef short sys_id_t;                 /* индекс системного процесса */
 04908	typedef struct {                        /* битовая карта для системных индексов */
 04909	  bitchunk_t chunk[BITMAP_CHUNKS(NR_SYS_PROCS)];
 04910	} sys_map_t;
 04911	
 04912	struct boot_image {
 04913	  proc_nr_t proc_nr;                    /* номер процесса для использования */
 04914	  task_t *initial_pc;                   /* начальная функция для заданий */
 04915	  int flags;                            /* флаги процесса */
 04916	  unsigned char quantum;                /* квант (счетчик тактов) */
 04917	  int priority;                         /* приоритет планирования */
 04918	  int stksize;                          /* размер стека для заданий */
 04919	  short trap_mask;                      /* разрешенные ловушки системных вызовов */
 04920	  bitchunk_t ipc_to;                    /* маска защиты передачи */
 04921	  long call_mask;                       /* защита системных вызовов */
 04922	  char proc_name[P_NAME_LEN];           /* имя в таблице процессов */
 04923	};
 04924	
 04925	struct memory {
 04926	  phys_clicks base;                     /* начальный адрес области */
 04927	  phys_clicks size;                     /* размер области */
 04928	};
 04929	
 04930	/* Ядро выводит диагностические сообщения в циклический буфер. */
 04931	struct kmessages {
 04932	  int km_next;                          /* следующий индекс для записи */
 04933	  int km_size;                          /* текущий объем в буфере */
 04934	  char km_buf[KMESS_BUF_SIZE];          /* буфер для сообщений */
 04935	};
 04936	
 04937	struct randomness {
 04938	  struct {
 04939	        int r_next;                             /* следующий индекс для записи */
 04940	        int r_size;                             /* число случайных элементов */
 04941	        unsigned short r_buf[RANDOM_ELEMENTS];  /* буфер для случайных данных */
 04942	  } bin[RANDOM_SOURCES];
 04943	};
 04944	
 04945	#if (CHIP == INTEL)
 04946	typedef unsigned reg_t;         /* машинный регистр */
 04947	
 04948	/* структура кадра стека определяется программным обеспечением, однако для эффективности
 04949	 * она задается так, чтобы ассемблерный код работал с ней с максимальной простотой.
 04950	 * Защищенный режим 80286 и все реальные режимы используют один и тот же кадр, формируемый
 04951	 * 16-разрядными регистрами. В реальном режиме отсутствует автоматическое переключение
 04952	 * стека, поэтому использование кадра 286 не приводит к большим потерям. Кадр 386 
 04953	 * отличается лишь разрядностью регистров (32 бита) и большим числом сегментных регистров.
 04954	 * Во избежание различий в коде регистры с большей разрядностью имеют те же имена.
 04955	 */
 04956	struct stackframe_s {           /* proc_ptr указывает сюда */
 04957	#if _WORD_SIZE == 4
 04958	  u16_t gs;                     /* последний элемент, помещенный в стек */
 04959	  u16_t fs;                     /*  ^ */
 04960	#endif
 04961	  u16_t es;                     /*  | */
 04962	  u16_t ds;                     /*  | */
 04963	  reg_t di;                     /* di – cx недоступны в C */
 04964	  reg_t si;                     /* порядок должен соответствовать pusha/popa */
 04965	  reg_t fp;                     /* bp */
 04966	  reg_t st;                     /* пространство для еще одной копии sp */
 04967	  reg_t bx;                     /*  | */
 04968	  reg_t dx;                     /*  | */
 04969	  reg_t cx;                     /*  | */
 04970	  reg_t retreg;                 /* ax и расположенные выше регистры помещаются в стек */
 04971	  reg_t retadr;                 /* адрес возврата для ассемблерного кода save() */
 04972	  reg_t pc;                     /*  ^  последний элемент, помещенный в стек прерыванием */
 04973	  reg_t cs;                     /*  | */
 04974	  reg_t psw;                    /*  | */
 04975	  reg_t sp;                     /*  | */
 04976	  reg_t ss;                     /* регистры, помещаемые в стек процессором при прерывании */
 04977	};
 04978	
 04979	struct segdesc_s {              /* дескриптор сегмента для защищенного режима */
 04980	  u16_t limit_low;
 04981	  u16_t base_low;
 04982	  u8_t base_middle;
 04983	  u8_t access;                  /* |P|DL|1|X|E|R|A| */
 04984	  u8_t granularity;             /* |G|X|0|A|LIMT| */
 04985	  u8_t base_high;
 04986	};
 04987	
 04988	typedef unsigned long irq_policy_t;     
 04989	typedef unsigned long irq_id_t; 
 04990	
 04991	typedef struct irq_hook {
 04992	  struct irq_hook *next;                /* следующий обработчик в цепи */
 04993	  int (*handler)(struct irq_hook *);    /* обработчик прерываний */
 04994	  int irq;                              /* номер вектора IRQ */ 
 04995	  int id;                               /* идентификатор этого обработчика */
 04996	  int proc_nr;                          /* NONE, если не используется */
 04997	  irq_id_t notify_id;                   /* идентификатор, возвращаемый при прерывании */
 04998	  irq_policy_t policy;                  /* битовая маска для политики */
 04999	} irq_hook_t;
 05000	
 05001	typedef int (*irq_handler_t)(struct irq_hook *);
 05002	
 05003	#endif /* (CHIP == INTEL) */
 05004	
 05005	#if (CHIP == M68000)
 05006	/* Типы, специфичные для M68000. */
 05007	#endif /* (CHIP == M68000) */
 05008	
 05009	#endif /* TYPE_H */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/proto.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 05100	/* Прототипы функций. */
 05101	
 05102	#ifndef PROTO_H
 05103	#define PROTO_H
 05104	
 05105	/* Объявления структур. */
 05106	struct proc;
 05107	struct timer;
 05108	
 05109	/* clock.c */
 05110	_PROTOTYPE( void clock_task, (void)                                     );
 05111	_PROTOTYPE( void clock_stop, (void)                                     );
 05112	_PROTOTYPE( clock_t get_uptime, (void)                                  );
 05113	_PROTOTYPE( unsigned long read_clock, (void)                            );
 05114	_PROTOTYPE( void set_timer, (struct timer *tp, clock_t t, tmr_func_t f) );
 05115	_PROTOTYPE( void reset_timer, (struct timer *tp)                        );
 05116	
 05117	/* main.c */
 05118	_PROTOTYPE( void main, (void)                                           );
 05119	_PROTOTYPE( void prepare_shutdown, (int how)                            );
 05120	
 05121	/* utility.c */
 05122	_PROTOTYPE( void kprintf, (const char *fmt, ...)                        );
 05123	_PROTOTYPE( void panic, (_CONST char *s, int n)                         );
 05124	
 05125	/* proc.c */
 05126	_PROTOTYPE( int sys_call, (int function, int src_dest, message *m_ptr)  );
 05127	_PROTOTYPE( int lock_notify, (int src, int dst)                         );
 05128	_PROTOTYPE( int lock_send, (int dst, message *m_ptr)                    );
 05129	_PROTOTYPE( void lock_enqueue, (struct proc *rp)                        );
 05130	_PROTOTYPE( void lock_dequeue, (struct proc *rp)                        );
 05131	
 05132	/* start.c */
 05133	_PROTOTYPE( void cstart, (U16_t cs, U16_t ds, U16_t mds,
 05134	                                U16_t parmoff, U16_t parmsize)          );
 05135	
 05136	/* system.c */
 05137	_PROTOTYPE( int get_priv, (register struct proc *rc, int proc_type)     );
 05138	_PROTOTYPE( void send_sig, (int proc_nr, int sig_nr)                    );
 05139	_PROTOTYPE( void cause_sig, (int proc_nr, int sig_nr)                   );
 05140	_PROTOTYPE( void sys_task, (void)                                       );
 05141	_PROTOTYPE( void get_randomness, (int source)                           );
 05142	_PROTOTYPE( int virtual_copy, (struct vir_addr *src, struct vir_addr *dst, 
 05143	                                vir_bytes bytes)                        );
 05144	#define numap_local(proc_nr, vir_addr, bytes) \
 05145	        umap_local(proc_addr(proc_nr), D, (vir_addr), (bytes))
 05146	_PROTOTYPE( phys_bytes umap_local, (struct proc *rp, int seg, 
 05147	                vir_bytes vir_addr, vir_bytes bytes)                    );
 05148	_PROTOTYPE( phys_bytes umap_remote, (struct proc *rp, int seg, 
 05149	                vir_bytes vir_addr, vir_bytes bytes)                    );
 05150	_PROTOTYPE( phys_bytes umap_bios, (struct proc *rp, vir_bytes vir_addr,
 05151	                vir_bytes bytes)                                        );
 05152	
 05153	/* exception.c */
 05154	_PROTOTYPE( void exception, (unsigned vec_nr)                           );
 05155	
 05156	/* i8259.c */
 05157	_PROTOTYPE( void intr_init, (int mine)                                  );
 05158	_PROTOTYPE( void intr_handle, (irq_hook_t *hook)                        );
 05159	_PROTOTYPE( void put_irq_handler, (irq_hook_t *hook, int irq,
 05160	                                                irq_handler_t handler)  );
 05161	_PROTOTYPE( void rm_irq_handler, (irq_hook_t *hook)                     );
 05162	
 05163	/* klib*.s */
 05164	_PROTOTYPE( void int86, (void)                                          );
 05165	_PROTOTYPE( void cp_mess, (int src,phys_clicks src_clicks,vir_bytes src_offset,
 05166	                phys_clicks dst_clicks, vir_bytes dst_offset)           );
 05167	_PROTOTYPE( void enable_irq, (irq_hook_t *hook)                         );
 05168	_PROTOTYPE( int disable_irq, (irq_hook_t *hook)                         );
 05169	_PROTOTYPE( u16_t mem_rdw, (U16_t segm, vir_bytes offset)               );
 05170	_PROTOTYPE( void phys_copy, (phys_bytes source, phys_bytes dest,
 05171	                phys_bytes count)                                       );
 05172	_PROTOTYPE( void phys_memset, (phys_bytes source, unsigned long pattern,
 05173	                phys_bytes count)                                       );
 05174	_PROTOTYPE( void phys_insb, (U16_t port, phys_bytes buf, size_t count)  );
 05175	_PROTOTYPE( void phys_insw, (U16_t port, phys_bytes buf, size_t count)  );
 05176	_PROTOTYPE( void phys_outsb, (U16_t port, phys_bytes buf, size_t count) );
 05177	_PROTOTYPE( void phys_outsw, (U16_t port, phys_bytes buf, size_t count) );
 05178	_PROTOTYPE( void reset, (void)                                          );
 05179	_PROTOTYPE( void level0, (void (*func)(void))                           );
 05180	_PROTOTYPE( void monitor, (void)                                        );
 05181	_PROTOTYPE( void read_tsc, (unsigned long *high, unsigned long *low)    );
 05182	_PROTOTYPE( unsigned long read_cpu_flags, (void)                        );
 05183	
 05184	/* mpx*.s */
 05185	_PROTOTYPE( void idle_task, (void)                                      );
 05186	_PROTOTYPE( void restart, (void)                                        );
 05187	
 05188	/* Следующие процедуры никогда не вызываются из C (полностью ассемблерные). */
 05189	
 05190	/* Обработчики исключений(реальный или защищенный режим) в числовом порядке. */
 05191	void _PROTOTYPE( int00, (void) ), _PROTOTYPE( divide_error, (void) );
 05192	void _PROTOTYPE( int01, (void) ), _PROTOTYPE( single_step_exception, (void) );
 05193	void _PROTOTYPE( int02, (void) ), _PROTOTYPE( nmi, (void) );
 05194	void _PROTOTYPE( int03, (void) ), _PROTOTYPE( breakpoint_exception, (void) );
 05195	void _PROTOTYPE( int04, (void) ), _PROTOTYPE( overflow, (void) );
 05196	void _PROTOTYPE( int05, (void) ), _PROTOTYPE( bounds_check, (void) );
 05197	void _PROTOTYPE( int06, (void) ), _PROTOTYPE( inval_opcode, (void) );
 05198	void _PROTOTYPE( int07, (void) ), _PROTOTYPE( copr_not_available, (void) );
 05199	void                              _PROTOTYPE( double_fault, (void) );
 05200	void                              _PROTOTYPE( copr_seg_overrun, (void) );
 05201	void                              _PROTOTYPE( inval_tss, (void) );
 05202	void                              _PROTOTYPE( segment_not_present, (void) );
 05203	void                              _PROTOTYPE( stack_exception, (void) );
 05204	void                              _PROTOTYPE( general_protection, (void) );
 05205	void                              _PROTOTYPE( page_fault, (void) );
 05206	void                              _PROTOTYPE( copr_error, (void) );
 05207	
 05208	/* Обработчики аппаратных прерываний. */
 05209	_PROTOTYPE( void hwint00, (void) );
 05210	_PROTOTYPE( void hwint01, (void) );
 05211	_PROTOTYPE( void hwint02, (void) );
 05212	_PROTOTYPE( void hwint03, (void) );
 05213	_PROTOTYPE( void hwint04, (void) );
 05214	_PROTOTYPE( void hwint05, (void) );
 05215	_PROTOTYPE( void hwint06, (void) );
 05216	_PROTOTYPE( void hwint07, (void) );
 05217	_PROTOTYPE( void hwint08, (void) );
 05218	_PROTOTYPE( void hwint09, (void) );
 05219	_PROTOTYPE( void hwint10, (void) );
 05220	_PROTOTYPE( void hwint11, (void) );
 05221	_PROTOTYPE( void hwint12, (void) );
 05222	_PROTOTYPE( void hwint13, (void) );
 05223	_PROTOTYPE( void hwint14, (void) );
 05224	_PROTOTYPE( void hwint15, (void) );
 05225	
 05226	/* Обработчики програмных прерываний в порядке номеров. */
 05227	_PROTOTYPE( void trp, (void) );
 05228	_PROTOTYPE( void s_call, (void) ), _PROTOTYPE( p_s_call, (void) );
 05229	_PROTOTYPE( void level0_call, (void) );
 05230	
 05231	/* protect.c */
 05232	_PROTOTYPE( void prot_init, (void)                                      );
 05233	_PROTOTYPE( void init_codeseg, (struct segdesc_s *segdp, phys_bytes base,
 05234	                vir_bytes size, int privilege)                          );
 05235	_PROTOTYPE( void init_dataseg, (struct segdesc_s *segdp, phys_bytes base,
 05236	                vir_bytes size, int privilege)                          );
 05237	_PROTOTYPE( phys_bytes seg2phys, (U16_t seg)                            );
 05238	_PROTOTYPE( void phys2seg, (u16_t *seg, vir_bytes *off, phys_bytes phys));
 05239	_PROTOTYPE( void enable_iop, (struct proc *pp)                          );
 05240	_PROTOTYPE( void alloc_segments, (struct proc *rp)                      );
 05241	
 05242	#endif /* PROTO_H */
 05243	
 05244	

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/glo.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 05300	#ifndef GLO_H
 05301	#define GLO_H
 05302	
 05303	/* Глобальные переменные, используемые в ядре. Этот файл содержит лишь их объявления;
 05304	 * место в памяти выделяется в table.c, так как EXTERN определяется как внешнее только
 05305	 * если определение _TABLE видимо. Для нескольких глобальных переменных мы предполагаем,
 05306	 * что компилятор по умолчанию инициализирует их нулями. 
 05307	 */
 05308	#ifdef _TABLE
 05309	#undef EXTERN
 05310	#define EXTERN
 05311	#endif
 05312	
 05313	#include <minix/config.h>
 05314	#include "config.h"
 05315	
 05316	/* Переменные, связанные с завершением работы MINIX. */
 05317	EXTERN char kernel_exception;           /* TRUE после системных исключений */
 05318	EXTERN char shutdown_started;           /* TRUE после завершения работы или перезагрузки */
 05319	
 05320	/* Информационные структуры ядра, группирующие его важнейшие данные. */
 05321	EXTERN phys_bytes aout;                 /* адрес заголовков a.out */
 05322	EXTERN struct kinfo kinfo;              /* информация ядра для пользователей */
 05323	EXTERN struct machine machine;          /* информация о компьютере для пользователей */
 05324	EXTERN struct kmessages kmess;          /* диагностические сообщения в ядре */
 05325	EXTERN struct randomness krandom;       /* собирает случайные данные ядра  */
 05326	
 05327	/* Информация о планировании процессов и счетчик повторных входов в ядро. */
 05328	EXTERN struct proc *prev_ptr;   /* предыдущий выполнявшийся процесс */
 05329	EXTERN struct proc *proc_ptr;   /* указатель на процесс, выполняющийся в текущий момент */
 05330	EXTERN struct proc *next_ptr;   /* процесс, который будет запущен после restart() */
 05331	EXTERN struct proc *bill_ptr;   /* процесс, которому начисляются такты часов */
 05332	EXTERN char k_reenter;          /* число повторных входов в ядро (меньше 1) */
 05333	EXTERN unsigned lost_ticks;     /* число тактов, подсчитанных вне таймерного задания */
 05334	
 05335	/* Переменные, связанные с прерываниями. */
 05336	EXTERN irq_hook_t irq_hooks[NR_IRQ_HOOKS];       /* обработчики общего назначения */
 05337	EXTERN irq_hook_t *irq_handlers[NR_IRQ_VECTORS]; /* список обработчиков прерываний */
 05338	EXTERN int irq_actids[NR_IRQ_VECTORS];           /* биты активных прерываний */
 05339	EXTERN int irq_use;                              /* карта всех используемых прерываний */
 05340	
 05341	/* Разное. */
 05342	EXTERN reg_t mon_ss, mon_sp;            /* стек монитора загрузки */
 05343	EXTERN int mon_return;                  /* true, если можно вернуться в монитор */
 05344	
 05345	/* Переменные, инициализируемые в других местах и объявляемые здесь как extern. */
 05346	extern struct boot_image image[];       /* процессы системного образа */
 05347	extern char *t_stack[];                 /* пространство стека заданий */
 05348	extern struct segdesc_s gdt[];          /* глобальная таблица дескрипторов */
 05349	
 05350	EXTERN _PROTOTYPE( void (*level0_func), (void) );
 05351	
 05352	#endif /* GLO_H */
 05353	
 05354	
 05355	
 05356	
 05357	



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/ipc.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 05400	#ifndef IPC_H
 05401	#define IPC_H
 05402	
 05403	/* Данный заголовочный файл определяет константы межпроцессного взаимодействия в MINIX.
 05404	 * Эти определения используются в файле proc.c.
 05405	 */
 05406	#include <minix/com.h>
 05407	
 05408	/* Маски и флаги для системных вызовов. */
 05409	#define SYSCALL_FUNC    0x0F    /* маска для функции системного вызова */
 05410	#define SYSCALL_FLAGS   0xF0    /* маска для флагов системного вызова */
 05411	#define NON_BLOCKING    0x10    /* упреждение блокировки, возврат ошибки */
 05412	
 05413	/* Номера системных вызовов, передаваемые при прерываниях ядра. Номера
 05414	 * специально определяются так, чтобы по установленным битам можно было легко 
 05415	 * определить, какие проверки следует выполнить в sys_call().
 05416	 */
 05417	#define SEND               1    /* 0 0 0 1 :  блокирующий вызов send */
 05418	#define RECEIVE            2    /* 0 0 1 0 :  блокирующий вызов receive */
 05419	#define SENDREC            3    /* 0 0 1 1 :  SEND + RECEIVE */
 05420	#define NOTIFY             4    /* 0 1 0 0 :  неблокирующее уведомление */
 05421	#define ECHO               8    /* 1 0 0 0 :  эхо-печать сообщения */
 05422	
 05423	/* Битовые маски, определяющие требуемые проверки. */
 05424	#define CHECK_PTR       0x0B    /* 1 0 1 1 :  проверка буфера сообщений */
 05425	#define CHECK_DST       0x05    /* 0 1 0 1 :  проверка получателя сообщения */
 05426	#define CHECK_SRC       0x02    /* 0 0 1 0 :  проверка отправителя сообщения */
 05427	
 05428	#endif /* IPC_H */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/proc.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 05500	#ifndef PROC_H
 05501	#define PROC_H
 05502	
 05503	/* Объявление таблицы процессов. Оно содержит все данные о процессах, включая регистры,
 05504	 * флаги, приоритеты планирования, карту памяти, учетные сведения, информацию, касающуюся
 05505	 * передачи сообщений и др. 
 05506	 *
 05507	 * Многие ассемблерные процедуры обращаются к полям этой таблицы. Смещения полей определены
 05508	 * в заголовочном файле ассемблера sconst.h. При изменении struct proc необходимо
 05509	 * соответствующим образом модифицировать файл sconst.h.
 05510	 */
 05511	#include <minix/com.h>
 05512	#include "protect.h"
 05513	#include "const.h"
 05514	#include "priv.h"
 05515	 
 05516	struct proc {
 05517	  struct stackframe_s p_reg;    /* регистры процессора, сохраненные в кадре стека */
 05518	  reg_t p_ldt_sel;              /* селектор в GDT с базой LDT и границей */
 05519	  struct segdesc_s p_ldt[2+NR_REMOTE_SEGS]; /* CS, DS и удаленные сегменты */
 05520	
 05521	  proc_nr_t p_nr;               /* номер этого процесса (для быстрого доступа) */
 05522	  struct priv *p_priv;          /* структура системных привилегий */
 05523	  char p_rts_flags;             /* SENDING, RECEIVING и т.п. */
 05524	
 05525	  char p_priority;              /* текущий приоритет планирования */
 05526	  char p_max_priority;          /* максимальный приоритет планирования */
 05527	  char p_ticks_left;            /* число оставшихся тактов */
 05528	  char p_quantum_size;          /* размер кванта в тактах */
 05529	
 05530	  struct mem_map p_memmap[NR_LOCAL_SEGS];   /* карта памяти (T, D, S) */
 05531	
 05532	  clock_t p_user_time;          /* время пользователя в тактах */
 05533	  clock_t p_sys_time;           /* системное время в тактах */
 05534	
 05535	  struct proc *p_nextready;     /* указатель на следующий готовый процесс */
 05536	  struct proc *p_caller_q;      /* начало списка процессов, желающих осуществить пересылку */
 05537	  struct proc *p_q_link;        /* связь со следующим процессом, желающим осуществить пересылку */
 05538	  message *p_messbuf;           /* указатель на буфер переданных сообщений */
 05539	  proc_nr_t p_getfrom;          /* отправитель сообщения, ожидаемого процессом */
 05540	  proc_nr_t p_sendto;           /* приемник сообщения, которое собирается отправить процесс */
 05541	
 05542	  sigset_t p_pending;           /* битовая карта активных сигналов ядра */
 05543	
 05544	  char p_name[P_NAME_LEN];      /* имя процесса, включая \0 */
 05545	};
 05546	
 05547	/* Биты флагов реального времени. Процесс может быть запущен, если p_rts_flags == 0. */
 05548	#define SLOT_FREE       0x01    /* запись процесса свободна */
 05549	#define NO_MAP          0x02    /* упреждает выполнение дочернего процесса без карты памяти */
 05550	#define SENDING         0x04    /* процесс блокирован во время выполнения SEND */
 05551	#define RECEIVING       0x08    /* процесс блокирован во время выполнения RECEIVE */
 05552	#define SIGNALED        0x10    /* устанавливается при получении нового сигнала ядра */
 05553	#define SIG_PENDING     0x20    /* не готов, пока обрабатывается сигнал */
 05554	#define P_STOP          0x40    /* устанавливается при трассировке процесса */
 05555	#define NO_PRIV         0x80    /* упреждает выполнение созданного системного процесса */
 05556	
 05557	/* Приоритеты планирования для p_priority. Значения должны начинаться с 0 (наивысший
 05558	 * приоритет) и возрастать. Приоритеты процессов загрузочного образа можно установить
 05559	 * в table.c. Процесс IDLE должен быть единственным процессом в своей очереди; процессы 
 05560	 * с низкими приоритетами не должны попадать в нее. 
 05561	 */
 05562	#define NR_SCHED_QUEUES   16    /* ДОЛЖНО быть равно минимальному приоритету + 1 */
 05563	#define TASK_Q             0    /* наивысший приоритет, для заданий ядра */
 05564	#define MAX_USER_Q         0    /* наивысший приоритет для пользовательских процессов */   
 05565	#define USER_Q             7    /* приоритет по умолчанию (должен соответствовать "вежливости" 0) */   
 05566	#define MIN_USER_Q        14    /* минимальный приоритет пользовательских процессов */
 05567	#define IDLE_Q            15    /* минимальный приоритет, его имеет только процесс IDLE */
 05568	
 05569	/* Магические адреса таблицы процессов. */
 05570	#define BEG_PROC_ADDR (&proc[0])
 05571	#define BEG_USER_ADDR (&proc[NR_TASKS])
 05572	#define END_PROC_ADDR (&proc[NR_TASKS + NR_PROCS])
 05573	
 05574	#define NIL_PROC          ((struct proc *) 0)           
 05575	#define NIL_SYS_PROC      ((struct proc *) 1)           
 05576	#define cproc_addr(n)     (&(proc + NR_TASKS)[(n)])
 05577	#define proc_addr(n)      (pproc_addr + NR_TASKS)[(n)]
 05578	#define proc_nr(p)        ((p)->p_nr)
 05579	
 05580	#define isokprocn(n)      ((unsigned) ((n) + NR_TASKS) < NR_PROCS + NR_TASKS)
 05581	#define isemptyn(n)       isemptyp(proc_addr(n)) 
 05582	#define isemptyp(p)       ((p)->p_rts_flags == SLOT_FREE)
 05583	#define iskernelp(p)      iskerneln((p)->p_nr)
 05584	#define iskerneln(n)      ((n) < 0)
 05585	#define isuserp(p)        isusern((p)->p_nr)
 05586	#define isusern(n)        ((n) >= 0)
 05587	
 05588	/* Таблица процессов и указатели на ее записи. Указатели ускоряют доступ, 
 05589	 * поскольку запись можно найти путем индексирования массива pproc_addr, а 
 05590	 * для того, чтобы вычислить адрес элемента i, нужно умножить значение i на
 05591	 * sizeof(struct proc). 
 05592	 */
 05593	EXTERN struct proc proc[NR_TASKS + NR_PROCS];   /* таблица процессов */
 05594	EXTERN struct proc *pproc_addr[NR_TASKS + NR_PROCS];
 05595	EXTERN struct proc *rdy_head[NR_SCHED_QUEUES]; /* указатели на начала списков готовых процессов */
 05596	EXTERN struct proc *rdy_tail[NR_SCHED_QUEUES]; /* указатели на концы списков готовых процессов */
 05597	
 05598	#endif /* PROC_H */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/sconst.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 05600	! Различные константы, используемые в ассемблерном коде.
 05601	W               =       _WORD_SIZE      ! Размер машинного слова.
 05602	
 05603	! Смещения в struct proc. Они ДОЛЖНЫ соответствовать файлу proc.h.
 05604	P_STACKBASE     =       0
 05605	GSREG           =       P_STACKBASE
 05606	FSREG           =       GSREG + 2       ! 386 вводит сегменты FS и GS
 05607	ESREG           =       FSREG + 2
 05608	DSREG           =       ESREG + 2
 05609	DIREG           =       DSREG + 2
 05610	SIREG           =       DIREG + W
 05611	BPREG           =       SIREG + W
 05612	STREG           =       BPREG + W       ! пространство для еще одного сегмента SP
 05613	BXREG           =       STREG + W
 05614	DXREG           =       BXREG + W
 05615	CXREG           =       DXREG + W
 05616	AXREG           =       CXREG + W
 05617	RETADR          =       AXREG + W       ! адрес возврата для вызова save()
 05618	PCREG           =       RETADR + W
 05619	CSREG           =       PCREG + W
 05620	PSWREG          =       CSREG + W
 05621	SPREG           =       PSWREG + W
 05622	SSREG           =       SPREG + W
 05623	P_STACKTOP      =       SSREG + W
 05624	P_LDT_SEL       =       P_STACKTOP
 05625	P_LDT           =       P_LDT_SEL + W
 05626	
 05627	Msize           =       9               ! размер сообщения в 32-разрядных словах



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/priv.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 05700	#ifndef PRIV_H
 05701	#define PRIV_H
 05702	
 05703	/* Объявление структуры системных привилегий. Оно задает флаги, маски системных вызовов,
 05704	 * синхронный сигнал таймера, привилегии ввода-вывода, активные аппаратные прерывания и
 05705	 * уведомления, и т. д.
 05706	 * Каждый системный процесс получает собственную структуру со свойствами, а всем
 05707	 * пользовательским процессам соответствует одна общая структура. Таким образом четко
 05708	 * разделяются обычные и привилегированные поля процессов и достигается экономия памяти.
 05709	 *
 05710	 * Изменения: 
 05711	 *   01 июля 2005       Создан.  (Jorrit N. Herder)    
 05712	 */
 05713	#include <minix/com.h>
 05714	#include "protect.h"
 05715	#include "const.h"
 05716	#include "type.h"
 05717	 
 05718	struct priv {
 05719	  proc_nr_t s_proc_nr;          /* номер процесса  */
 05720	  sys_id_t s_id;                /* индекс этой системной структуры */
 05721	  short s_flags;                /* PREEMTIBLE, BILLABLE и т. д. */
 05722	
 05723	  short s_trap_mask;            /* разрешенные ловушки системных вызовов */
 05724	  sys_map_t s_ipc_from;         /* разрешенные процессы-отправители */
 05725	  sys_map_t s_ipc_to;           /* разрешенные процессы-приемникы */
 05726	  long s_call_mask;             /* разрешенные вызовы ядра */
 05727	
 05728	  sys_map_t s_notify_pending;   /* битовая карта с активными уведомлениями */
 05729	  irq_id_t s_int_pending;       /* активные аппаратные прерывания */
 05730	  sigset_t s_sig_pending;       /* активные сигналы */
 05731	
 05732	  timer_t s_alarm_timer;        /* синхронный сигнальный таймер */ 
 05733	  struct far_mem s_farmem[NR_REMOTE_SEGS];  /* удаленная карта памяти */
 05734	  reg_t *s_stack_guard;         /* слово защиты стека для заданий ядра */
 05735	};
 05736	
 05737	/* слово защиты для стеков заданий. */
 05738	#define STACK_GUARD     ((reg_t) (sizeof(reg_t) == 2 ? 0xBEEF :  0xDEADBEEF))
 05739	
 05740	/* Биты флагов системных свойств. */
 05741	#define PREEMPTIBLE     0x01    /* Заданий ядра не могут быть вытеснены */
 05742	#define BILLABLE        0x04    /* Некоторым процессам не начисляется время */
 05743	#define SYS_PROC        0x10    /* Системные процессы являются привилегированными */
 05744	#define SENDREC_BUSY    0x20    /* sendrec() в работе */
 05745	
 05746	/* Магические адреса таблицы системных структур. */
 05747	#define BEG_PRIV_ADDR (&priv[0])
 05748	#define END_PRIV_ADDR (&priv[NR_SYS_PROCS])
 05749	
 05750	#define priv_addr(i)      (ppriv_addr)[(i)]
 05751	#define priv_id(rp)       ((rp)->p_priv->s_id)
 05752	#define priv(rp)          ((rp)->p_priv)
 05753	
 05754	#define id_to_nr(id)    priv_addr(id)->s_proc_nr
 05755	#define nr_to_id(nr)    priv(proc_addr(nr))->s_id
 05756	
 05757	/* Таблица системных структур и указателей на отдельные записи таблицы. Указатели
 05758	 * ускоряют доступ, поскольку запись можно найти путем индексирования массива 
 05759	 * psys_addr array, а для того, чтобы вычислить адрес элемента i, нужно умножить
 05760	 * значение i на sizeof(struct sys). 
 05761	 */
 05762	EXTERN struct priv priv[NR_SYS_PROCS];          /* таблица свойств системы */
 05763	EXTERN struct priv *ppriv_addr[NR_SYS_PROCS];   /* прямые указатели на записи */
 05764	
 05765	/* Непривилегированные пользовательские процессы имеют общую структуру привилегий. Этот
 05766	 * идентификатор должен быть постоянным, поскольку используется для проверки записей масок.
 05767	 */
 05768	#define USER_PRIV_ID    0
 05769	
 05770	/* Проверка способности системы к загрузке – таблица привилегий
 05771	 * должна иметь достаточный размер для процессов
 05772	 * загрузочного образа. 
 05773	 */
 05774	#if (NR_BOOT_PROCS > NR_SYS_PROCS)
 05775	#error NR_SYS_PROCS must be larger than NR_BOOT_PROCS
 05776	#endif
 05777	
 05778	#endif /* PRIV_H */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/protect.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 05800	/* Константы для защищенного режима. */
 05801	
 05802	/* Размеры таблиц. */
 05803	#define GDT_SIZE (FIRST_LDT_INDEX + NR_TASKS + NR_PROCS) 
 05804	                                        /* спец. и LDT */
 05805	#define IDT_SIZE (IRQ8_VECTOR + 8)      /* только до наивысшего вектора */
 05806	#define LDT_SIZE (2 + NR_REMOTE_SEGS)   /* CS, DS и удаленные сегменты */
 05807	
 05808	/* Фиксированные глобальные дескрипторы.  От 1 до 7 задаются BIOS. */
 05809	#define GDT_INDEX            1  /* Дескриптор GDT */
 05810	#define IDT_INDEX            2  /* Дескриптор IDT */
 05811	#define DS_INDEX             3  /* DS ядра */
 05812	#define ES_INDEX             4  /* ES ядра (386:  флаг 4 Гбайт при запуске) */
 05814	#define CS_INDEX             6  /* CS ядра */
 05815	#define MON_CS_INDEX         7  /* для BIOS (386:  наблюдение CS при запуске) */
 05816	#define TSS_INDEX            8  /* TSS ядра */
 05817	#define DS_286_INDEX         9  /* сырой 16-разрядный сегмент источника */
 05818	#define ES_286_INDEX        10  /* сырой 16-разрядный сегмент приемника */
 05819	#define A_INDEX             11  /* сегмент памяти 64K по адресу A0000 */
 05820	#define B_INDEX             12  /* сегмент памяти 64K по адресу B0000 */
 05821	#define C_INDEX             13  /* сегмент памяти 64K по адресу C0000 */
 05822	#define D_INDEX             14  /* сегмент памяти 64K по адресу D0000 */
 05823	#define FIRST_LDT_INDEX     15  /* остальные дескрипторы принадлежат LDT */
 05824	
 05825	#define GDT_SELECTOR      0x08  /* (GDT_INDEX * DESC_SIZE) плохо для asld */
 05826	#define IDT_SELECTOR      0x10  /* (IDT_INDEX * DESC_SIZE) */
 05827	#define DS_SELECTOR       0x18  /* (DS_INDEX * DESC_SIZE) */
 05828	#define ES_SELECTOR       0x20  /* (ES_INDEX * DESC_SIZE) */
 05829	#define FLAT_DS_SELECTOR  0x21  /* менее привилегированный ES */
 05830	#define SS_SELECTOR       0x28  /* (SS_INDEX * DESC_SIZE) */
 05831	#define CS_SELECTOR       0x30  /* (CS_INDEX * DESC_SIZE) */
 05832	#define MON_CS_SELECTOR   0x38  /* (MON_CS_INDEX * DESC_SIZE) */
 05833	#define TSS_SELECTOR      0x40  /* (TSS_INDEX * DESC_SIZE) */
 05834	#define DS_286_SELECTOR   0x49  /* (DS_286_INDEX*DESC_SIZE+TASK_PRIVILEGE) */
 05835	#define ES_286_SELECTOR   0x51  /* (ES_286_INDEX*DESC_SIZE+TASK_PRIVILEGE) */
 05836	
 05837	/* Фиксированные локальные дескрипторы. */
 05838	#define CS_LDT_INDEX         0  /* CS процесса */
 05839	#define DS_LDT_INDEX         1  /* DS=ES=FS=GS=SS процесса */
 05840	#define EXTRA_LDT_INDEX      2  /* запись первой дополнительной LDT */
 05841	
 05842	/* Привилегии. */
 05843	#define INTR_PRIVILEGE       0  /* ядро и обработчики прерываний */
 05844	#define TASK_PRIVILEGE       1  /* заданияядра */
 05845	#define USER_PRIVILEGE       3  /* серверы и пользовательские процессы */
 05846	
 05847	/* аппаратные константы 286. */
 05848	
 05849	/* Номера векторов исключений. */
 05850	#define BOUNDS_VECTOR        5  /* неудачная проверка границ */
 05851	#define INVAL_OP_VECTOR      6  /* неверный код команды */
 05852	#define COPROC_NOT_VECTOR    7  /* сопроцессор недоступен */
 05853	#define DOUBLE_FAULT_VECTOR  8
 05854	#define COPROC_SEG_VECTOR    9  /* переполнение сегмента сопроцессора */
 05855	#define INVAL_TSS_VECTOR    10  /* некорректный TSS */
 05856	#define SEG_NOT_VECTOR      11  /* сегмент отсутствует */
 05857	#define STACK_FAULT_VECTOR  12  /* исключение стека */
 05858	#define PROTECTION_VECTOR   13  /* общая защита */
 05859	
 05860	/* Биты селектора. */
 05861	#define TI                0x04  /* индикатор таблицы */
 05862	#define RPL               0x03  /* уровень привилегий запрашивающего */
 05863	
 05864	/* Смещения в структуре дескриптора . */
 05865	#define DESC_BASE            2  /* для base_low */
 05866	#define DESC_BASE_MIDDLE     4  /* для base_middle */
 05867	#define DESC_ACCESS          5  /* для access byte */
 05868	#define DESC_SIZE            8  /* sizeof (struct segdesc_s) */
 05869	
 05870	/* Размеры базы и границы, и сдвиги. */
 05871	#define BASE_MIDDLE_SHIFT   16  /* сдвиг базы --> base_middle */
 05872	
 05873	/* Биты байтов доступа и типа. */
 05874	#define PRESENT           0x80  /* устанавливается для присутствующего дескриптора */
 05875	#define DPL               0x60  /* маска уровня привилегий дескриптора */
 05876	#define DPL_SHIFT            5
 05877	#define SEGMENT           0x10  /* устанавливается для дескрипторов сегментов */
 05878	
 05879	/* Биты байта доступа. */
 05880	#define EXECUTABLE        0x08  /* устанавливается для исполняемого сегмента */
 05881	#define CONFORMING        0x04  /* устанавливается для конформного сегмента, если он является исполняемым */
 05882	#define EXPAND_DOWN       0x04  /* устанавливается для сегмента, растущего вниз, если он не является исполняемым */
 05883	#define READABLE          0x02  /* устанавливается для читаемого сегмента, если он не является исполняемым */
 05884	#define WRITEABLE         0x02  /* устанавливается для сегмента с возможностью записи, если он не является исполняемым */
 05885	#define TSS_BUSY          0x02  /* устанавливается, если дескриптор TSS занят */
 05886	#define ACCESSED          0x01  /* устанавливается, если к сегменту осуществляется доступ */
 05887	
 05888	/* Специальные типы дескрипторов. */
 05889	#define AVL_286_TSS          1  /* доступный TSS 286  */
 05890	#define LDT                  2  /* локальная таблица дескрипторов */
 05891	#define BUSY_286_TSS         3  /* устанавливается прозрачно для программного обеспечения */
 05892	#define CALL_286_GATE        4  /* не используется  */
 05893	#define TASK_GATE            5  /* используется только отладчиком */
 05894	#define INT_286_GATE         6  /* вентиль прерывания, используемый всеми векторами */
 05895	#define TRAP_286_GATE        7  /* не используется */
 05896	
 05897	/* Дополнительные аппаратные константы 386. */
 05898	
 05899	/* Номера векторов исключений. */
 05900	#define PAGE_FAULT_VECTOR   14
 05901	#define COPROC_ERR_VECTOR   16  /* ошибка сопроцессора */
 05902	
 05903	/* Смещения в структуре дескриптора. */
 05904	#define DESC_GRANULARITY     6  /* для байта гранулярности */
 05905	#define DESC_BASE_HIGH       7  /* для base_high */
 05906	
 05907	/* Размеры базы и границы, и сдвиги. */
 05908	#define BASE_HIGH_SHIFT     24  /* сдвиг для базы --> base_high */
 05909	#define BYTE_GRAN_MAX   0xFFFFFL   /* максимальный размер для сегмента с байтовой гранулярностью */
 05910	#define GRANULARITY_SHIFT   16  /* сдвиг для границы --> granularity */
 05911	#define OFFSET_HIGH_SHIFT   16  /* сдвиг для смещения --> offset_high */
 05912	#define PAGE_GRAN_SHIFT     12  /* дополнительный сдвиг для границ со страничной гранулярностью */
 05913	
 05914	/* Биты байта типа. */
 05915	#define DESC_386_BIT  0x08 /* Типы процессора 386 получаются путем операции OR с этим значением */
 05916	                                /* LDT и TASK_GATE не нуждаются в этом */
 05917	
 05918	/* Байт гранулярности. */
 05919	#define GRANULAR          0x80  /* устанавливается для гранулярности 4K */
 05920	#define DEFAULT           0x40  /* устанавливается для 32-разрядных умолчаний (исполняемый сегмент) */
 05921	#define BIG               0x40  /* устанавливается для сегмента, растущего вниз */
 05922	#define AVL               0x10  /* 0 для готовности */
 05923	#define LIMIT_HIGH        0x0F  /* маска для старших битов границы */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/table.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 06000	/* Объектный файл, соответствующий файлу "table.c", содержит большую часть данных ядра.
 06001	 * Переменные, объявленные в файлах *.h, снабжены спецификатором EXTERN, как в объявлении
 06002	 *
 06003	 *    EXTERN int x;
 06004	 *
 06005	 * Обычно EXTERN означает внешнее определение, поэтому при включении переменных в другой файл
 06006	 * память под них не выделяется. Если бы спецификатор EXTERN отсутствовал:
 06007	 *
 06008	 *    int x;
 06009	 *
 06010	 * то при включении заголовочного файла в несколько файлов исходного кода переменная'x' 
 06011	 * оказалась бы объявленной несколько раз. Хотя одни редакторы связей допускают это, другие
 06012	 * считают это ошибкой, поэтому в заголовочных файлах переменные обычно определяются как
 06013	 * внешние. Тем не менее, переменная должна получить реальное воплощение где-либо; это делается
 06014	 * здесь путем переопределения EXTERN как нулевой строки. В результате включение всех  
 06015	 * файлов *.h в table.c фактически приводит к выделению памяти под переменные.  
 06016	 *
 06017	 * Различные переменные не могли быть объявлены как EXTERN и объявлены как PUBLIC
 06018	 * или PRIVATE. Это объясняется тем, что внешние переменные не инициализируются по
 06019	 * умолчанию. Если такие переменные используются совместно, они также должны быть
 06020	 * объявлены в одном из файлов *.h без инициализации. Примеры: boot_image (в этом файле),
 06021	 * 'idt' и 'gdt' (protect.c). 
 06022	 *
 06023	 * Изменения: 
 06024	 *    02 августа 2005: созданы привилегии и минимальный загрузочный образ (Jorrit N. Herder)
 06025	 *    17 октября 2004: обновлены приведенные ранее комментарии (Jorrit N. Herder)
 06026	 *    01 мая 2004: изменена структура образа системы (Jorrit N. Herder)
 06027	 */
 06028	#define _TABLE
 06029	
 06030	#include "kernel.h"
 06031	#include "proc.h"
 06032	#include "ipc.h"
 06033	#include <minix/com.h>
 06034	#include <ibm/int86.h>
 06035	
 06036	/* Определение размеров стеков заданий ядра, включенных в образ системы. */
 06037	#define NO_STACK        0
 06038	#define SMALL_STACK     (128 * sizeof(char *))
 06039	#define IDL_S   SMALL_STACK     /* 3 intr, 3 temps, 4 db для Intel */
 06040	#define HRD_S   NO_STACK        /* пустое задание, использует стек ядра */
 06041	#define TSK_S   SMALL_STACK     /* таймерное и системное задания */
 06042	
 06043	/* Стековое пространство для все заданий. Объявлено как (char *) для корректировки. */
 06044	#define TOT_STACK_SPACE (IDL_S + HRD_S + (2 * TSK_S))
 06045	PUBLIC char *t_stack[TOT_STACK_SPACE / sizeof(char *)];
 06046	        
 06047	/* Определение флагов для различных типов процессов. */
 06048	#define IDL_F   (SYS_PROC | PREEMPTIBLE | BILLABLE)     /* задание бездействия */
 06049	#define TSK_F   (SYS_PROC)                              /* задание ядра */
 06050	#define SRV_F   (SYS_PROC | PREEMPTIBLE)                /* системные службы */
 06051	#define USR_F   (BILLABLE | PREEMPTIBLE)                /* пользовательские процессы */
 06052	
 06053	/* Определение ловушек системных вызовов для различных типов процессов. Эти маски вызовов
 06054	 * определяют, какие ловушки разрешено использовать процессу.
 06055	 */
 06056	#define TSK_T   (1 << RECEIVE)                  /* таймерное и системное задания */
 06057	#define SRV_T   (~0)                            /* системные службы */
 06058	#define USR_T   ((1 << SENDREC) | (1 << ECHO))  /* пользовательские процессы */
 06059	
 06060	/* Маски передачи определяют, кому процессы могут адресовать сообщения и уведомления.
 06061	 * Приведенные здесь значения используются для процессов загрузочного образа. Предполагается,
 06062	 * что код инициализации в main() приводит в соответствие маски s_nr_to_id() для
 06063	 * процессов загрузочного образа. Таким образом, маску передачи, определенную здесь, 
 06064	 * можно непосредственно скопировать в map[0] фактической маски передачи. Структура
 06065	 * привилегий 0 совместно используется пользовательскими процессами. 
 06066	 */
 06067	#define s(n)            (1 << s_nr_to_id(n))
 06068	#define SRV_M (~0)
 06069	#define SYS_M (~0)
 06070	#define USR_M (s(PM_PROC_NR) | s(FS_PROC_NR) | s(RS_PROC_NR))
 06071	#define DRV_M (USR_M | s(SYSTEM) | s(CLOCK) | s(LOG_PROC_NR) | s(TTY_PROC_NR))
 06072	
 06073	/* Определение вызовов ядра, которые разрешено выполнять процессам. Это выглядит не очень 
 06074	 * хорошо, однако нам необходимо определять права доступа индивидуально для каждого вызова.
 06075	 * Обратите внимание на то, что все биты сервера реинкарнации установлены, поскольку ему
 06076	 * необходимо распространять права на службы, которые он запускает.
 06077	 */
 06078	#define c(n)    (1 << ((n)-KERNEL_CALL))
 06079	#define RS_C    ~0      
 06080	#define PM_C    ~(c(SYS_DEVIO) | c(SYS_SDEVIO) | c(SYS_VDEVIO) \
 06081	    | c(SYS_IRQCTL) | c(SYS_INT86))
 06082	#define FS_C    (c(SYS_KILL) | c(SYS_VIRCOPY) | c(SYS_VIRVCOPY) | c(SYS_UMAP) \
 06083	    | c(SYS_GETINFO) | c(SYS_EXIT) | c(SYS_TIMES) | c(SYS_SETALARM))
 06084	#define DRV_C   (FS_C | c(SYS_SEGCTL) | c(SYS_IRQCTL) | c(SYS_INT86) \
 06085	    | c(SYS_DEVIO) | c(SYS_VDEVIO) | c(SYS_SDEVIO)) 
 06086	#define MEM_C   (DRV_C | c(SYS_PHYSCOPY) | c(SYS_PHYSVCOPY))
 06087	
 06088	/* Таблица системного образа содержит все программы, являющиеся частью загрузочного образа.
 06089	 * Порядок записей здесь ДОЛЖЕН соответствовать порядку программ загрузочного образа, и все
 06090	 * задания ядра идут первыми.
 06091	 * Каждая запись содержит номер процесса, флаги, величину кванта (qs), приоритет очереди,
 06092	 * разрешенные ловушки, ipc-маску и имя процесса в таблице процессов. Для заданий ядра также
 06093	 * указаны начальное значение счетчика программ и размер стека.
 06094	 */
 06095	PUBLIC struct boot_image image[] = {
 06096	/* номер процесса, тип, флаги, квант, очередь, стек, ловушки, ipc-маска, вызов, имя */ 
 06097	 { IDLE,  idle_task, IDL_F,  8, IDLE_Q, IDL_S,     0,     0,     0, "IDLE"  },
 06098	 { CLOCK,clock_task, TSK_F, 64, TASK_Q, TSK_S, TSK_T,     0,     0, "CLOCK" },
 06099	 { SYSTEM, sys_task, TSK_F, 64, TASK_Q, TSK_S, TSK_T,     0,     0, "SYSTEM"},
 06100	 { HARDWARE,      0, TSK_F, 64, TASK_Q, HRD_S,     0,     0,     0, "KERNEL"},
 06101	 { PM_PROC_NR,    0, SRV_F, 32,      3, 0,     SRV_T, SRV_M,  PM_C, "pm"    },
 06102	 { FS_PROC_NR,    0, SRV_F, 32,      4, 0,     SRV_T, SRV_M,  FS_C, "fs"    },
 06103	 { RS_PROC_NR,    0, SRV_F,  4,      3, 0,     SRV_T, SYS_M,  RS_C, "rs"    },
 06104	 { TTY_PROC_NR,   0, SRV_F,  4,      1, 0,     SRV_T, SYS_M, DRV_C, "tty"   },
 06105	 { MEM_PROC_NR,   0, SRV_F,  4,      2, 0,     SRV_T, DRV_M, MEM_C, "memory"},
 06106	 { LOG_PROC_NR,   0, SRV_F,  4,      2, 0,     SRV_T, SYS_M, DRV_C, "log"   },
 06107	 { DRVR_PROC_NR,  0, SRV_F,  4,      2, 0,     SRV_T, SYS_M, DRV_C, "driver"},
 06108	 { INIT_PROC_NR,  0, USR_F,  8, USER_Q, 0,     USR_T, USR_M,     0, "init"  },
 06109	};
 06110	
 06111	/* Проверка размера таблицы системного образа на этапе компиляции, а также того, что 
 06112	 * первый элемент ipc-маски имеет достаточно битов для всех процессов, включенных 
 06113	 * в образ.  
 06114	 * В случае обнаружения проблемы размер массива 'dummy' будет отрицательным, 
 06115	 * что вызовет ошибку при компиляции. При этом никакого выделения памяти не произойдет,
 06116	 * поскольку переменная 'dummy' определена как внешняя.
 06117	 */
 06118	extern int dummy[(NR_BOOT_PROCS==sizeof(image)/
 06119	        sizeof(struct boot_image))?1: -1];
 06120	extern int dummy[(BITCHUNK_BITS > NR_BOOT_PROCS - 1) ? 1 :  -1];
 06121	




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/mpx.s
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 06200	#
 06201	! Выбор между версиями кода загрузки Minix для 8086 и 386.
 06202	
 06203	#include <minix/config.h>
 06204	#if _WORD_SIZE == 2
 06205	#include "mpx88.s"
 06206	#else
 06207	#include "mpx386.s"
 06208	#endif


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/mpx386.s
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 06300	# 
 06301	! Файл mpx386.s включается в файл mpx.s, когда Minix компилируется для 32-разрядных
 06302	! процессоров Intel. Для 16-разрядных процессоров при компиляции используется файл mpx88.s.
 06303	
 06304	! Этот файл является частью нижнего уровня ядра MINIX.  (еще одна часть размещена в файле
 06305	! "proc.c".). На нижнем уровне выполняется переключение процессов и обработка сообщений.
 06306	! Он также содержит ассемблерный код запуска для Minix и 32-разрядные обработчики 
 06307	! прерываний. Этот код взаимодействует с кодом файла "start.c" для создания нужного
 06308	! окружения для функции main().
 06309	
 06310	! Каждый переход в ядро осуществляется через данный файл. Переходы могут быть вложенными.
 06311	! Начальный вход в ядро возможен по системному вызову (например, для передачи или получения 
 06312	! сообщения), исключению или аппаратному прерыванию; повторные входы возможны только по 
 06313	! аппаратным прерываниям.  Число повторных входов регистрируется в переменной "k_reenter".
 06314	! Это важно для принятия решения о необходимости переключения стека ядра и для защиты кода
 06315	! передачи сообщений в "proc.c".
 06316	
 06317	! При передаче сообщений большая часть информации о состоянии компьютера сохраняется в таблице
 06318	! proc. (некоторые регистры сохранять не нужно). Затем стек переключается в "k_stack" и
 06319	! прерывания снова разрешаются. Далее вызывается обработчик системного вызова на языке C.
 06320	! После возврата прерывания снова запрещаются и выполняется процедура перезапуска,
 06321	! завершающая незаконченные прерывания и запускающая процесс или задание, чей указатель
 06322	! находится в "proc_ptr".
 06323	
 06324	! Обработчики аппаратных прерываний выполняют то же самое, за следующими исключениями: (1) 
 06325	! необходимо сохранять состояние целиком. (2) Число обработчиков слишком велико, чтобы 
 06326	! возлагать эту задачу на них. Вместо этого вызывается специальная процедура. Экономия
 06327	! нескольких циклов достигается за счет размещения в стеке адреса процедуры перезапуска.
 06328	! (3) Если стек уже переключен, переключение стека обходится. (4) Прерывания от главного 
 06329	! контроллера 8259 разрешаются централизованно в функции save(). (5) Каждый обработчик
 06330	! маскирует свою линию прерываний при помощи 8259 до разрешения других маскируемых
 06331	! прерываний и снимает маску по окончании обслуживания. Это ограничивает уровень 
 06332	! вложенности до числа линий и защищает обработчик от самого себя.
 06333	
 06334	! Для связи с монитором загрузки некоторые константы помещаются в начало 
 06335	! сегмента кода. Они играют вспомогательную роль при чтении данных в  
 06336	! в начале процесса загрузки, поскольку необходимо считать лишь первый
 06337	! сектор файла.
 06338	
 06339	! Часть пространства для хранения данных также отведена и в конце файла. Эти данные
 06340	! окажутся в начале сегмента данных ядра и будут считаны и изменены монитором загрузки
 06341	! перед запуском ядра.
 06342	
 06343	! разделы
 06344	
 06345	.sect .text
 06346	begtext: 
 06347	.sect .rom
 06348	begrom: 
 06349	.sect .data
 06350	begdata: 
 06351	.sect .bss
 06352	begbss: 
 06353	
 06354	#include <minix/config.h>
 06355	#include <minix/const.h>
 06356	#include <minix/com.h>
 06357	#include <ibm/interrupt.h>
 06358	#include "const.h"
 06359	#include "protect.h"
 06360	#include "sconst.h"
 06361	
 06362	/* Выбранные смещения tss 386. */
 06363	#define TSS3_S_SP0      4
 06364	
 06365	! Экспортируемые функции
 06366	! Обратите внимание: в языке ассемблера применение директивы .define к имени 
 06367	! функции не эквивалентно прототипу в языке C - она лишь позволяет установить 
 06368	! связь с объектом, объявленным в ассемблерном коде, однако не создает сам
 06369	! объект.
 06370	
 06371	.define _restart
 06372	.define save
 06373	
 06374	.define _divide_error
 06375	.define _single_step_exception
 06376	.define _nmi
 06377	.define _breakpoint_exception
 06378	.define _overflow
 06379	.define _bounds_check
 06380	.define _inval_opcode
 06381	.define _copr_not_available
 06382	.define _double_fault
 06383	.define _copr_seg_overrun
 06384	.define _inval_tss
 06385	.define _segment_not_present
 06386	.define _stack_exception
 06387	.define _general_protection
 06388	.define _page_fault
 06389	.define _copr_error
 06390	
 06391	.define _hwint00        ! обработчики аппаратных прерываний
 06392	.define _hwint01
 06393	.define _hwint02
 06394	.define _hwint03
 06395	.define _hwint04
 06396	.define _hwint05
 06397	.define _hwint06
 06398	.define _hwint07
 06399	.define _hwint08
 06400	.define _hwint09
 06401	.define _hwint10
 06402	.define _hwint11
 06403	.define _hwint12
 06404	.define _hwint13
 06405	.define _hwint14
 06406	.define _hwint15
 06407	
 06408	.define _s_call
 06409	.define _p_s_call
 06410	.define _level0_call
 06411	
 06412	! Экспортируемые переменные.
 06413	.define begbss
 06414	.define begdata
 06415	
 06416	.sect .text
 06417	!*===========================================================================*
 06418	!*                              MINIX                                        *
 06419	!*===========================================================================*
 06420	MINIX:                          ! точка входа в ядро MINIX
 06421	        jmp     over_flags      ! пропустить несколько следующих байтов
 06422	        .data2  CLICK_SHIFT     ! для монитора: гранулярность памяти
 06423	flags: 
 06424	        .data2  0x01FD          ! флаги монитора загрузки: 
 06425	                                !   вызов в режиме 386, создать bss, создать стек,
 06426	                                !   загружать в верхнее адресное пространство, не объединять,
 06427	                                !   с возвратом, использование общих прерываний,
 06428	                                !   вектор памяти, возврат из нового загрузочного кода
 06429	        nop                     ! дополнительный байт для синхронизации дизассемблера
 06430	over_flags: 
 06431	
 06432	! Создание C-кадра в стеке монитора. (монитор корректно устанавливает cs и ds. Дескриптор
 06433	! ss продолжает указывать на сегмент данных монитора.)
 06434	        movzx   esp, sp         ! стек монитора 16-разрядный
 06435	        push    ebp
 06436	        mov     ebp, esp
 06437	        push    esi
 06438	        push    edi
 06439	        cmp     4(ebp), 0       ! вектор возврата монитора
 06440	        jz      noret           ! не равен 0, если возврат возможен
 06441	        inc     (_mon_return)
 06442	noret:   mov     (_mon_sp), esp ! сохранить указатель стека для возврата в будущем
 06443	
 06444	! Копировать глобальную таблицу дескрипторов монитора в адресное пространство ядра и
 06445	! переключиться в него. Затем prot_init() может обновить ее с немедленным результатом.
 06446	
 06447	        sgdt    (_gdt+GDT_SELECTOR)             ! получить gdtr монитора
 06448	        mov     esi, (_gdt+GDT_SELECTOR+2)      ! абсолютный адрес GDT
 06449	        mov     ebx, _gdt                       ! адрес GDT ядра
 06450	        mov     ecx, 8*8                        ! копирование восьми дескрипторов
 06451	copygdt: 
 06452	 eseg   movb    al, (esi)
 06453	        movb    (ebx), al
 06454	        inc     esi
 06455	        inc     ebx
 06456	        loop    copygdt
 06457	        mov     eax, (_gdt+DS_SELECTOR+2)       ! базовый адрес данных ядра
 06458	        and     eax, 0x00FFFFFF                 ! только 24 бита
 06459	        add     eax, _gdt                       ! eax = vir2phys(gdt)
 06460	        mov     (_gdt+GDT_SELECTOR+2), eax      ! установить базовый адрес GDT
 06461	        lgdt    (_gdt+GDT_SELECTOR)             ! переключиться в GDT ядра
 06462	
 06463	! Перейти к параметрам загрузки, установить сегментные регистры и стек.
 06464	        mov     ebx, 8(ebp)     ! смещение параметров загрузки
 06465	        mov     edx, 12(ebp)    ! длина параметров загрузки
 06466	        mov     eax, 16(ebp)    ! адрес заголовков a.out
 06467	        mov     (_aout), eax
 06468	        mov     ax, ds          ! данные ядра
 06469	        mov     es, ax
 06470	        mov     fs, ax
 06471	        mov     gs, ax
 06472	        mov     ss, ax
 06473	        mov     esp, k_stktop   ! установка указателя стека на вершину стека ядра
 06474	
 06475	! вызов C-кода загрузки для установки окружения, необходимого для работы функции main().
 06476	        push    edx
 06477	        push    ebx
 06478	        push    SS_SELECTOR
 06479	        push    DS_SELECTOR
 06480	        push    CS_SELECTOR
 06481	        call    _cstart         ! cstart(cs, ds, mds, parmoff, parmlen)
 06482	        add     esp, 5*4
 06483	
 06484	! Перезагрузка gdtr, idtr и сегментных регистров в глобальную таблицу дескрипторов,
 06485	! сформированную prot_init().
 06486	
 06487	        lgdt    (_gdt+GDT_SELECTOR)
 06488	        lidt    (_gdt+IDT_SELECTOR)
 06489	
 06490	        jmpf    CS_SELECTOR: csinit
 06491	csinit: 
 06492	    o16 mov     ax, DS_SELECTOR
 06493	        mov     ds, ax
 06494	        mov     es, ax
 06495	        mov     fs, ax
 06496	        mov     gs, ax
 06497	        mov     ss, ax
 06498	    o16 mov     ax, TSS_SELECTOR        ! другие TSS не используются 
 06499	        ltr     ax
 06500	        push    0                       ! установка флагов в последнее удачное состояние,
 06501	        popf                            ! очистка вложенного задания и разрешение прерываний
 06502	
 06503	        jmp     _main                   ! main()
 06504	
 06505	
 06506	!*===========================================================================*
 06507	!*                          обработчики прерываний                           *
 06508	!*       обработчики прерываний для защищенного 32-разрядного режима 386     *
 06509	!*===========================================================================*
 06510	
 06511	!*===========================================================================*
 06512	!*                              hwint00 - 07                                 *
 06513	!*===========================================================================*
 06514	! обратите внимание на то, что этот макрос внешне напоминает подпрограмму.
 06515	#define hwint_master(irq)       \
 06516	        call    save                    /* сохранение состояния прерванного процесса */;\
 06517	        push    (_irq_handlers+4*irq)   /* irq_handlers[irq]              */;\
 06518	        call    _intr_handle            /* intr_handle(irq_handlers[irq]) */;\
 06519	        pop     ecx                                                         ;\
 06520	        cmp     (_irq_actids+4*irq), 0  /* активно ли еще прерывание?     */;\
 06521	        jz      0f                                                          ;\
 06522	        inb     INT_CTLMASK             /* получение текущей маски */       ;\
 06523	        orb     al, [1<<irq]            /* маскирование прерывания */       ;\
 06524	        outb    INT_CTLMASK             /* запрещение прерывания          */;\
 06525	0:      movb    al, END_OF_INT                                              ;\
 06526	        outb    INT_CTL                 /* разрешение прерывание главного 8259     */;\
 06527	        ret                             /* перезапуск процесса (возможно, другого) */
 06528	
 06529	! Каждая из этих точек входа — раскрытие макроса hwint_master
 06530	        .align  16
 06531	_hwint00:                ! Подпрограмма обработки прерывания 0 (часы).
 06532	        hwint_master(0)
 06533	
 06534	        .align  16
 06535	_hwint01:                ! Подпрограмма обработки прерывания 1 (клавиатура)
 06536	        hwint_master(1)
 06537	
 06538	        .align  16
 06539	_hwint02:                ! Подпрограмма обработки прерывания 2 (каскад!)
 06540	        hwint_master(2)
 06541	
 06542	        .align  16
 06543	_hwint03:                ! Подпрограмма обработки прерывания 3 (второй последовательный порт)
 06544	        hwint_master(3)
 06545	
 06546	        .align  16
 06547	_hwint04:                ! Подпрограмма обработки прерывания 4 (первый последовательный порт)
 06548	        hwint_master(4)
 06549	
 06550	        .align  16
 06551	_hwint05:                ! Подпрограмма обработки прерывания 5 (жесткий диск XT)
 06552	        hwint_master(5)
 06553	
 06554	        .align  16
 06555	_hwint06:                ! Подпрограмма обработки прерывания 6 (дисковод для дискет)
 06556	        hwint_master(6)
 06557	
 06558	        .align  16
 06559	_hwint07:                ! Подпрограмма обработки прерывания 7 (принтер)
 06560	        hwint_master(7)
 06561	
 06562	!*===========================================================================*
 06563	!*                              hwint08 - 15                                 *
 06564	!*===========================================================================*
 06565	! обратите внимание на то, что этот макрос внешне напоминает подпрограмму.
 06566	#define hwint_slave(irq)        \
 06567	        call    save                    /* сохранение состояния прерванного процесса */;\
 06568	        push    (_irq_handlers+4*irq)   /* irq_handlers[irq]                         */;\
 06569	        call    _intr_handle            /* intr_handle(irq_handlers[irq]) */;\
 06570	        pop     ecx                                                         ;\
 06571	        cmp     (_irq_actids+4*irq), 0  /* активно ли еще прерывание?     */;\
 06572	        jz      0f                                                          ;\
 06573	        inb     INT2_CTLMASK                                                ;\
 06574	        orb     al, [1<<[irq-8]]                                            ;\
 06575	        outb    INT2_CTLMASK            /* запрещение прерывания          */;\
 06576	0:      movb    al, END_OF_INT                                              ;\
 06577	        outb    INT_CTL                 /* разрешение прерывания главного 8259           */;\
 06578	        outb    INT2_CTL                /* разрешение прерывания подчиненного 8259            */;\
 06579	        ret                             /* перезапуск процесса (возможно, другого)      */
 06580	
 06581	! Каждая из этих точек входа – раскрытие макроса hwint_slave
 06582	        .align  16
 06583	_hwint08:                ! Подпрограмма обработки прерывания 8 (часы реального времени)
 06584	        hwint_slave(8)
 06585	
 06586	        .align  16
 06587	_hwint09:                ! Подпрограмма обработки прерывания 9 (перенаправленное прерывание)
 06588	        hwint_slave(9)
 06589	
 06590	        .align  16
 06591	_hwint10:                ! Подпрограмма обработки прерывания 10
 06592	        hwint_slave(10)
 06593	
 06594	        .align  16
 06595	_hwint11:                ! Подпрограмма обработки прерывания 11
 06596	        hwint_slave(11)
 06597	
 06598	        .align  16
 06599	_hwint12:                ! Подпрограмма обработки прерывания 12
 06600	        hwint_slave(12)
 06601	
 06602	        .align  16
 06603	_hwint13:                ! Подпрограмма обработки прерывания 13 (исключение FPU)
 06604	        hwint_slave(13)
 06605	
 06606	        .align  16
 06607	_hwint14:                ! Подпрограмма обработки прерывания 14 (жесткий диск AT)
 06608	        hwint_slave(14)
 06609	
 06610	        .align  16
 06611	_hwint15:                ! Подпрограмма обработки прерывания 15
 06612	        hwint_slave(15)
 06613	
 06614	!*===========================================================================*
 06615	!*                            save                                           *
 06616	!*===========================================================================*
 06617	! Сохранение в защищенном режиме.
 06618	! Это значительно проще, чем в режиме 8086, поскольку стек уже указывает на
 06619	! таблицу процессов или переключен на стек ядра.
 06620	
 06621	        .align  16
 06622	save: 
 06623	        cld                     ! установка определенного значения флага направления
 06624	        pushad                  ! сохранение "общих" регистров
 06625	    o16 push    ds              ! сохранение ds
 06626	    o16 push    es              ! сохранение es
 06627	    o16 push    fs              ! сохранение fs
 06628	    o16 push    gs              ! сохранение gs
 06629	        mov     dx, ss          ! ss — сегмент данных ядра
 06630	        mov     ds, dx          ! загрузка остальных сегментов ядра
 06631	        mov     es, dx          ! ядро не использует fs и gs
 06632	        mov     eax, esp        ! подготовка к возврату
 06633	        incb    (_k_reenter)    ! от -1, если нет повторного входа
 06634	        jnz     set_restart1    ! стек уже переключен на ядро
 06635	        mov     esp, k_stktop
 06636	        push    _restart        ! создание адреса возврата для обработчика прерывания
 06637	        xor     ebp, ebp        ! для трассировки стека
 06638	        jmp     RETADR-P_STACKBASE(eax)
 06639	
 06640	        .align  4
 06641	set_restart1: 
 06642	        push    restart1
 06643	        jmp     RETADR-P_STACKBASE(eax)
 06644	
 06645	!*===========================================================================*
 06646	!*                              _s_call                                      *
 06647	!*===========================================================================*
 06648	        .align  16
 06649	_s_call: 
 06650	_p_s_call: 
 06651	        cld                     ! установка определенного значения флага направления
 06652	        sub     esp, 6*4        ! пропустить RETADR, eax, ecx, edx, ebx, est
 06653	        push    ebp             ! стек уже указывает на таблицу процессов
 06654	        push    esi
 06655	        push    edi
 06656	    o16 push    ds
 06657	    o16 push    es
 06658	    o16 push    fs
 06659	    o16 push    gs
 06660	        mov     dx, ss
 06661	        mov     ds, dx
 06662	        mov     es, dx
 06663	        incb    (_k_reenter)
 06664	        mov     esi, esp        ! предполагается P_STACKBASE == 0
 06665	        mov     esp, k_stktop
 06666	        xor     ebp, ebp        ! для трассировки стека
 06667	                                ! конец встроенного сохранения
 06668	                                ! теперь установить параметры sys_call()
 06669	        push    ebx             ! указатель на сообщение пользователя
 06670	        push    eax             ! источник/получатель
 06671	        push    ecx             ! SEND/RECEIVE/и то, и другое
 06672	        call    _sys_call       ! sys_call(function, src_dest, m_ptr)
 06673	                                ! вызывающая процедура явно указана в proc_ptr
 06674	        mov     AXREG(esi), eax ! вызов sys_call ДОЛЖЕН СОХРАНИТЬ si
 06675	
 06676	! Код перезапуска процесса/задания.
 06677	
 06678	!*===========================================================================*
 06679	!*                              restart                                      *
 06680	!*===========================================================================*
 06681	_restart: 
 06682	
 06683	! Перезапуск текущего или следующего процесса (если задан). 
 06684	
 06685	        cmp     (_next_ptr), 0          ! запланирован ли другой процесс?
 06686	        jz      0f
 06687	        mov     eax, (_next_ptr)
 06688	        mov     (_proc_ptr), eax        ! запланировать новый процесс
 06689	        mov     (_next_ptr), 0
 06690	0:      mov     esp, (_proc_ptr)        ! в предположении P_STACKBASE == 0
 06691	        lldt    P_LDT_SEL(esp)          ! разрешить сегментные дескрипторы процесса
 06692	        lea     eax, P_STACKTOP(esp)    ! подготовка к следующему прерыванию:
 06693	        mov     (_tss+TSS3_S_SP0), eax  ! состояние должно быть сохранено в таблице процессов
 06694	restart1: 
 06695	        decb    (_k_reenter)
 06696	    o16 pop     gs
 06697	    o16 pop     fs
 06698	    o16 pop     es
 06699	    o16 pop     ds
 06700	        popad
 06701	        add     esp, 4          ! пропустить адрес возврата
 06702	        iretd                   ! продолжить процесс
 06703	
 06704	!*===========================================================================*
 06705	!*                          обработчики исключений                           *
 06706	!*===========================================================================*
 06707	_divide_error: 
 06708	        push    DIVIDE_VECTOR
 06709	        jmp     exception
 06710	
 06711	_single_step_exception: 
 06712	        push    DEBUG_VECTOR
 06713	        jmp     exception
 06714	
 06715	_nmi: 
 06716	        push    NMI_VECTOR
 06717	        jmp     exception
 06718	
 06719	_breakpoint_exception: 
 06720	        push    BREAKPOINT_VECTOR
 06721	        jmp     exception
 06722	
 06723	_overflow: 
 06724	        push    OVERFLOW_VECTOR
 06725	        jmp     exception
 06726	
 06727	_bounds_check: 
 06728	        push    BOUNDS_VECTOR
 06729	        jmp     exception
 06730	
 06731	_inval_opcode: 
 06732	        push    INVAL_OP_VECTOR
 06733	        jmp     exception
 06734	
 06735	_copr_not_available: 
 06736	        push    COPROC_NOT_VECTOR
 06737	        jmp     exception
 06738	
 06739	_double_fault: 
 06740	        push    DOUBLE_FAULT_VECTOR
 06741	        jmp     errexception
 06742	
 06743	_copr_seg_overrun: 
 06744	        push    COPROC_SEG_VECTOR
 06745	        jmp     exception
 06746	
 06747	_inval_tss: 
 06748	        push    INVAL_TSS_VECTOR
 06749	        jmp     errexception
 06750	
 06751	_segment_not_present: 
 06752	        push    SEG_NOT_VECTOR
 06753	        jmp     errexception
 06754	
 06755	_stack_exception: 
 06756	        push    STACK_FAULT_VECTOR
 06757	        jmp     errexception
 06758	
 06759	_general_protection: 
 06760	        push    PROTECTION_VECTOR
 06761	        jmp     errexception
 06762	
 06763	_page_fault: 
 06764	        push    PAGE_FAULT_VECTOR
 06765	        jmp     errexception
 06766	
 06767	_copr_error: 
 06768	        push    COPROC_ERR_VECTOR
 06769	        jmp     exception
 06770	
 06771	!*===========================================================================*
 06772	!*                              exception                                    *
 06773	!*===========================================================================*
 06774	! Вызывается для всех исключений, не возвращающих код ошибки.
 06775	
 06776	        .align  16
 06777	exception: 
 06778	 sseg   mov     (trap_errno), 0         ! очистка trap_errno
 06779	 sseg   pop     (ex_number)
 06780	        jmp     exception1
 06781	
 06782	!*===========================================================================*
 06783	!*                              errexception                                 *
 06784	!*===========================================================================*
 06785	! Вызывается для всех исключений, возвращающих код ошибки.
 06786	
 06787	        .align  16
 06788	errexception: 
 06789	 sseg   pop     (ex_number)
 06790	 sseg   pop     (trap_errno)
 06791	exception1:                             ! Для всех исключений
 06792	        push    eax                     ! eax - рабочий регистр 
 06793	        mov     eax, 0+4(esp)           ! старый регистр eip
 06794	 sseg   mov     (old_eip), eax
 06795	        movzx   eax, 4+4(esp)           ! старый регистр cs
 06796	 sseg   mov     (old_cs), eax
 06797	        mov     eax, 8+4(esp)           ! старый регистр eflags
 06798	 sseg   mov     (old_eflags), eax
 06799	        pop     eax
 06800	        call    save
 06801	        push    (old_eflags)
 06802	        push    (old_cs)
 06803	        push    (old_eip)
 06804	        push    (trap_errno)
 06805	        push    (ex_number)
 06806	        call    _exception              ! (ex_number, trap_errno, old_eip,
 06807	                                        !       old_cs, old_eflags)
 06808	        add     esp, 5*4
 06809	        ret
 06810	
 06811	!*===========================================================================*
 06812	!*                              level0_call                                  *
 06813	!*===========================================================================*
 06814	_level0_call: 
 06815	        call    save
 06816	        jmp     (_level0_func)
 06817	
 06818	!*===========================================================================*
 06819	!*                              data                                         *
 06820	!*===========================================================================*
 06821	
 06822	.sect .rom      ! Перед таблицей строк
 06823	        .data2  0x526F          ! магическое число – должно быть первым в данных
 06824	
 06825	.sect .bss
 06826	k_stack: 
 06827	        .space  K_STACK_BYTES   ! стек ядра
 06828	k_stktop:                       ! вершина стека ядра
 06829	        .comm   ex_number, 4
 06830	        .comm   trap_errno, 4
 06831	        .comm   old_eip, 4
 06832	        .comm   old_cs, 4
 06833	        .comm   old_eflags, 4


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/start.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 06900	/* Данный файл содержит C-код загрузки Minix для процессоров Intel.
 06901	 * Он взаимодействует с mpx.s для создания нужного окружения для работы функции main().
 06902	 *
 06903	 * Данный код выполняется в режиме 16-разрядного ядра; для 286 процессора, возможно,
 06904	 * потребуется переключение в защищенный режим.
 06905	 * Для 32-разрядного ядра код уже выполняется в защищенном режиме, однако селекторы, назначенные
 06906	 * BIOS, остаются неизменными и прерывания запрещены. Таким образом, дескрипторы необходимо
 06907	 * перезагрузить, а прерывания разрешить.
 06908	 */
 06909	
 06910	#include "kernel.h"
 06911	#include "protect.h"
 06912	#include "proc.h"
 06913	#include <stdlib.h>
 06914	#include <string.h>
 06915	
 06916	FORWARD _PROTOTYPE( char *get_value, (_CONST char *params, _CONST char *key));
 06917	/*===========================================================================*
 06918	 *                              cstart                                       *
 06919	 *===========================================================================*/
 06920	PUBLIC void cstart(cs, ds, mds, parmoff, parmsize)
 06921	U16_t cs, ds;                   /* сегменты кода и данных ядра */
 06922	U16_t mds;                      /* сегмент данных монитора */
 06923	U16_t parmoff, parmsize;        /* смещение и длина параметров загрузки */
 06924	{
 06925	/* Выполнение системных инициализаций до вызова main(). Большинство параметров определяются
 06926	 * с использованием строк окружения, передаваемых загрузчиком MINIX.
 06927	 */
 06928	  char params[128*sizeof(char *)];              /* параметры монитора загрузки */
 06929	  register char *value;                         /* значение в паре ключ=значение */
 06930	  extern int etext, end;
 06931	
 06932	  /* Определение, является ли режим защищенным; процессоры 386 и выше предполагают
 06933	   * защищенный режим. Это действие должно быть первым, так как его результат требуется,.
 06934	   * например, функции seg2phys(). Для процессоров 286 мы пока не можем принять решение 
 06935	   * об использовании защищенного режима. Это делается позже.
 06936	   */
 06937	#if _WORD_SIZE != 2
 06938	  machine.protected = 1;        
 06939	#endif
 06940	
 06941	  /* Местоположение ядра и монитора. */
 06942	  kinfo.code_base = seg2phys(cs);
 06943	  kinfo.code_size = (phys_bytes) &etext;        /* размер сегмента кода */
 06944	  kinfo.data_base = seg2phys(ds);
 06945	  kinfo.data_size = (phys_bytes) &end;          /* размер сегмента данных */
 06946	
 06947	  /* Инициализация дескрипторов защищенного режима. */
 06948	  prot_init();
 06949	
 06950	  /* Копирование параметров загрузки в локальный буфер. */
 06951	  kinfo.params_base = seg2phys(mds) + parmoff;
 06952	  kinfo.params_size = MIN(parmsize,sizeof(params)-2);
 06953	  phys_copy(kinfo.params_base, vir2phys(params), kinfo.params_size);
 06954	
 06955	  /* Запись различной информации для серверов, выполняемых в пространстве пользователя. */
 06956	  kinfo.nr_procs = NR_PROCS;
 06957	  kinfo.nr_tasks = NR_TASKS;
 06958	  strncpy(kinfo.release, OS_RELEASE, sizeof(kinfo.release));
 06959	  kinfo.release[sizeof(kinfo.release)-1] = '\0';
 06960	  strncpy(kinfo.version, OS_VERSION, sizeof(kinfo.version));
 06961	  kinfo.version[sizeof(kinfo.version)-1] = '\0';
 06962	  kinfo.proc_addr = (vir_bytes) proc;
 06963	  kinfo.kmem_base = vir2phys(0);
 06964	  kinfo.kmem_size = (phys_bytes) &end;  
 06965	
 06966	  /* Процессор:  86, 186, 286, 386, ... 
 06967	   * Определение, нужен ли защищенный режим, для более старых компьютеров.
 06968	   */
 06969	  machine.processor=atoi(get_value(params, "processor")); 
 06970	#if _WORD_SIZE == 2
 06971	  machine.protected = machine.processor >= 286;         
 06972	#endif
 06973	  if (! machine.protected) mon_return = 0;
 06974	
 06975	  /* Шина: XT, AT или MCA? */
 06976	  value = get_value(params, "bus");
 06977	  if (value == NIL_PTR || strcmp(value, "at") == 0) {
 06978	      machine.pc_at = TRUE;                     /* оборудование, совместимое с PC-AT */
 06979	  } else if (strcmp(value, "mca") == 0) {
 06980	      machine.pc_at = machine.ps_mca = TRUE;    /* PS/2 с микроканалом */
 06981	  }
 06982	
 06983	  /* Тип видеоадаптера:  */
 06984	  value = get_value(params, "video");           /* EGA или VGA */
 06985	  if (strcmp(value, "ega") == 0) machine.vdu_ega = TRUE;
 06986	  if (strcmp(value, "vga") == 0) machine.vdu_vga = machine.vdu_ega = TRUE;
 06987	
 06988	  /* Возврат в код ассемблера для переключения в защищенный режим (если 286), 
 06989	   * перезагрузка селекторов и вызов main().
 06990	   */
 06991	}
	
 06993	/*===========================================================================*
 06994	 *                              get_value                                    *
 06995	 *===========================================================================*/
 06996	
 06997	PRIVATE char *get_value(params, name)
 06998	_CONST char *params;                            /* параметры монитора загрузки */
 06999	_CONST char *name;                              /* ключ для поиска */
 07000	{
 07001	/* Получение значения окружения – версия getenv для ядра, чтобы избежать формирования
 07002	 * обычного массива окружения.
 07003	 */
 07004	  register _CONST char *namep;
 07005	  register char *envp;
 07006	
 07007	  for (envp = (char *) params; *envp != 0;) {
 07008	        for (namep = name; *namep != 0 && *namep == *envp; namep++, envp++)
 07009	                ;
 07010	        if (*namep == '\0' && *envp == '=') return(envp + 1);
 07011	        while (*envp++ != 0)
 07012	                ;
 07013	  }
 07014	  return(NIL_PTR);
 07015	}





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/main.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 07100	/* Этот файл содержит основную программу MINIX и код завершения работы операционной системы.
 07101	 * Процедура main() инициализирует систему и запускает ее, настраивая таблицу 
 07102	 * процессов, векторы прерываний и планируя каждое задание на запуск для
 07103	 * самоинициализации.
 07104	 * Подпрограмма shutdown() выполняет противоположное действие и завершает работу MINIX. 
 07105	 *
 07106	 * В данном файле имеются следующие точки входа: 
 07107	 *   main:               основная программа MINIX
 07108	 *   prepare_shutdown:   подготовка MINIX к завершению
 07109	 *
 07110	 * Изменения: 
 07111	 *   24 ноября 2004    упрощенная версия main() с системным образом  (Jorrit N. Herder)
 07112	 *   20 августа 2004   новые версии функций prepare_shutdown() и shutdown()  (Jorrit N. Herder)
 07113	 */
 07114	#include "kernel.h"
 07115	#include <signal.h>
 07116	#include <string.h>
 07117	#include <unistd.h>
 07118	#include <a.out.h>
 07119	#include <minix/callnr.h>
 07120	#include <minix/com.h>
 07121	#include "proc.h"
 07122	
 07123	/* Объявления прототипов для закрытых функций. */
 07124	FORWARD _PROTOTYPE( void announce, (void));     
 07125	FORWARD _PROTOTYPE( void shutdown, (timer_t *tp));
 07126	
 07127	/*===========================================================================*
 07128	 *                              main                                         *
 07129	 *===========================================================================*/
 07130	PUBLIC void main()
 07131	{
 07132	/* Запуск MINIX */
 07133	  struct boot_image *ip;        /* указатель на загрузочный образ */
 07134	  register struct proc *rp;     /* указатель на процесс */
 07135	  register struct priv *sp;     /* указатель на структуру привилегий */
 07136	  register int i, s;
 07137	  int hdrindex;                 /* индекс массива заголовков a.out */
 07138	  phys_clicks text_base;
 07139	  vir_clicks text_clicks, data_clicks;
 07140	  reg_t ktsb;                   /* база стека задания ядра */
 07141	  struct exec e_hdr;            /* для копии заголовка a.out */
 07142	
 07143	  /* Инициализация контроллера прерываний. */
 07144	  intr_init(1);
 07145	
 07146	  /* Очистка таблицы процессов. Объявление всех записей пустыми и задание соответствий
 07147	   * для макросов proc_addr() и proc_nr(). Те же действия для таблицы структур привилегий
 07148	   * системных процессов. 
 07149	   */
 07150	  for (rp = BEG_PROC_ADDR, i = -NR_TASKS; rp < END_PROC_ADDR; ++rp, ++i) {
 07151	        rp->p_rts_flags = SLOT_FREE;            /* инициализация свободной записи */
 07152	        rp->p_nr = i;                           /* номер процесса по указателю */
 07153	        (pproc_addr + NR_TASKS)[i] = rp;        /* указатель на процесс по номеру */
 07154	  }
 07155	  for (sp = BEG_PRIV_ADDR, i = 0; sp < END_PRIV_ADDR; ++sp, ++i) {
 07156	        sp->s_proc_nr = NONE;                   /* инициализация свободной записи */
 07157	        sp->s_id = i;                           /* индекс структуры привилегий */
 07158	        ppriv_addr[i] = sp;                     /* указатель на структуру привилегий по номеру */
 07159	  }
 07160	
 07161	  /* Ввод записей заданий и серверов в таблице процессов. Стеки заданий ядра 
 07162	   * инициализируются массивом, находящимся в пространстве данных. Стеки серверов
 07163	   * уже добавлены в сегмент данных монитором, поэтому указатель стека установлен
 07164	   * на конец сегмента данных. Для процессора 8086 все процессы находятся в нижней
 07165	   * области памяти. В случае процессора 386 в нижней области находится лишь ядро, а
 07166	   * все остальные компоненты операционной системы загружаются в расширенную память.
 07167	   */
 07168	
 07169	  /* Стеки заданий. */
 07170	  ktsb = (reg_t) t_stack;
 07171	
 07172	  for (i=0; i < NR_BOOT_PROCS; ++i) {
 07173	        ip = &image[i];                         /* атрибуты процессов */
 07174	        rp = proc_addr(ip->proc_nr);            /* получение указателя процесса */
 07175	        rp->p_max_priority = ip->priority;      /* максимальный приоритет при планировании */
 07176	        rp->p_priority = ip->priority;          /* текущий приоритет */
 07177	        rp->p_quantum_size = ip->quantum;       /* размер кванта в тактах */
 07178	        rp->p_ticks_left = ip->quantum;         /* текущий кредит */
 07179	        strncpy(rp->p_name, ip->proc_name, P_NAME_LEN); /* задание имени процесса */
 07180	        (void) get_priv(rp, (ip->flags & SYS_PROC));    /* назначение структуры */
 07181	        priv(rp)->s_flags = ip->flags;                  /* флаги процесса*/
 07182	        priv(rp)->s_trap_mask = ip->trap_mask;          /* разрешенные ловушки */
 07183	        priv(rp)->s_call_mask = ip->call_mask;          /* маска вызовов ядра */
 07184	        priv(rp)->s_ipc_to.chunk[0] = ip->ipc_to;       /* разграничение приемников */
 07185	        if (iskerneln(proc_nr(rp))) {           /* является ли процесс частью ядра? */ 
 07186	                if (ip->stksize > 0) {          /* размер стека HARDWARE равен 0 */
 07187	                        rp->p_priv->s_stack_guard = (reg_t *) ktsb;
 07188	                        *rp->p_priv->s_stack_guard = STACK_GUARD;
 07189	                }
 07190	                ktsb += ip->stksize;    /* указатель на верхнюю границу стека */
 07191	                rp->p_reg.sp = ktsb;    /* начальный указатель стека этого задания */
 07192	                text_base = kinfo.code_base >> CLICK_SHIFT;
 07193	                                        /* все процессы, находящиеся в ядре, */
 07194	                hdrindex = 0;           /* используют первый заголовок a.out */
 07195	        } else {
 07196	                hdrindex = 1 + i-NR_TASKS;      /* серверы, драйверы, INIT */
 07197	        }
 07198	
 07199	        /* Программа начальной загрузки создала массив заголовков a.out по абсолютному
 07200	         * адресу 'aout'. Запись одного элемента в переменную e_hdr.
 07201	         */
 07202	        phys_copy(aout + hdrindex * A_MINHDR, vir2phys(&e_hdr),
 07203	                                                (phys_bytes) A_MINHDR);
 07204	        /* Преобразование адресов в клики и создание карты памяти процесса */
 07205	        text_base = e_hdr.a_syms >> CLICK_SHIFT;
 07206	        text_clicks = (e_hdr.a_text + CLICK_SIZE-1) >> CLICK_SHIFT;
 07207	        if (!(e_hdr.a_flags & A_SEP)) text_clicks = 0;     /* общие код и данные */
 07208	        data_clicks = (e_hdr.a_total + CLICK_SIZE-1) >> CLICK_SHIFT;
 07209	        rp->p_memmap[T].mem_phys = text_base;
 07210	        rp->p_memmap[T].mem_len  = text_clicks;
 07211	        rp->p_memmap[D].mem_phys = text_base + text_clicks;
 07212	        rp->p_memmap[D].mem_len  = data_clicks;
 07213	        rp->p_memmap[S].mem_phys = text_base + text_clicks + data_clicks;
 07214	        rp->p_memmap[S].mem_vir  = data_clicks; /* пусто – стек находится в пространстве данных */
 07215	
 07216	        /* Ввод начальных значений регистров. Слово состояния процессора для заданий
 07217	         * отличается от слова состояния процессора для других процессов, поскольку задания
 07218	         * имеют доступ к вводу-выводу, что запрещено менее привилегированным процессам 
 07219	         */
 07220	        rp->p_reg.pc = (reg_t) ip->initial_pc;
 07221	        rp->p_reg.psw = (iskernelp(rp)) ? INIT_TASK_PSW :  INIT_PSW;
 07222	
 07223	        /* Инициализация указателя стека сервера. Он сдвигается на одно слово вниз, чтобы
 07224	         * дать файлу crtso.s пространство для использования в качестве "argc".
 07225	         */
 07226	        if (isusern(proc_nr(rp))) {             /* является ли процесс пользовательским? */ 
 07227	                rp->p_reg.sp = (rp->p_memmap[S].mem_vir +
 07228	                                rp->p_memmap[S].mem_len) << CLICK_SHIFT;
 07229	                rp->p_reg.sp -= sizeof(reg_t);
 07230	        }
 07231	        
 07232	        /* Установка готовности. Задание HARDWARE никогда не бывает готово. */
 07233	        if (rp->p_nr != HARDWARE) {
 07234	                rp->p_rts_flags = 0;            /* процесс можно запустить при отсутствии флагов */
 07235	                lock_enqueue(rp);               /* добавление в очереди планирования */
 07236	        } else {
 07237	                rp->p_rts_flags = NO_MAP;       /* предотвращение запуска */
 07238	        }
 07239	
 07240	        /* В защищенном режиме должны быть выделены сегменты кода и данных. */
 07241	        alloc_segments(rp);
 07242	  }
 07243	
 07244	  /* Мы не собираемся завершать работу системы. */
 07245	  shutdown_started = 0;
 07246	
 07247	  /* Теперь система MINIX готова. Все процессы загрузочного образа находятся в очереди
 07248	   * готовых процессов. Возврат в ассемблерный код для запуска текущего процесса. 
 07249	   */
 07250	  bill_ptr = proc_addr(IDLE);           /* должен на что-то указывать */
 07251	  announce();                           /* печать стартового сообщения MINIX */
 07252	  restart();
 07253	}
	
 07255	/*===========================================================================*
 07256	 *                              announce                                     *
 07257	 *===========================================================================*/
 07258	PRIVATE void announce(void)
 07259	{
 07260	  /* Отображение стартового сообщения MINIX. */
 07261	  kprintf("MINIX %s.%s."  
 07262	      "Copyright 2006, Vrije Universiteit, Amsterdam, The Netherlands\n", 
 07263	      OS_RELEASE, OS_VERSION);
 07264	
 07265	  /* Реальный или защищенный 16/32-разрядный режим? */
 07266	  kprintf("Executing in %s mode.\n\n",
 07267	      machine.protected ? "32-bit protected" :  "real");
 07268	}
	
 07270	/*===========================================================================*
 07271	 *                              prepare_shutdown                             *
 07272	 *===========================================================================*/
 07273	PUBLIC void prepare_shutdown(how)
 07274	int how;
 07275	{
 07276	/* Эта функция подготавливает MINIX к завершению. */
 07277	  static timer_t shutdown_timer;
 07278	  register struct proc *rp; 
 07279	  message m;
 07280	
 07281	  /* Отображение отладочных дампов при аварии. Обеспечение доступности задания терминала
 07282	   * для обработки путем неблокирующей отправки. Предполагается,
 07283	   * что задание терминала вызовет функцию sys_abort() после завершения работы с дампами.
 07284	   */
 07285	  if (how == RBT_PANIC) {
 07286	      m.m_type = PANIC_DUMPS;
 07287	      if (nb_send(TTY_PROC_NR,&m)==OK)  /* не блокировать, если терминал не готов */
 07288	          return;                       /* ожидание sys_abort() от терминала*/
 07289	  }
 07290	
 07291	  /* Передача сигнала всем незавершенным системным процессам, чтобы информировать их 
 07292	   * об окончании работы ядра MINIX. Сервер пользовательского пространства должен реализовывать
 07293	   * корректную последовательность завершения работы. Этот механизм полезен в качестве
 07294	   * резервного при аварии системы. Системные процессы получают возможность выполнить свой
 07295	   * завершающий код, например, синхронизировать файловую систему или переключить терминал
 07296	   * на первую консоль. 
 07297	   */
 07298	  kprintf("Sending SIGKSTOP to system processes ...\n"); 
 07299	  for (rp=BEG_PROC_ADDR; rp<END_PROC_ADDR; rp++) {
 07300	      if (!isemptyp(rp) && (priv(rp)->s_flags & SYS_PROC) && !iskernelp(rp))
 07301	          send_sig(proc_nr(rp), SIGKSTOP);
 07302	  }
 07303	
 07304	  /* Завершение работы. Теперь диагностика может вести себя по-другому. */
 07305	  shutdown_started = 1;
 07306	
 07307	  /* Уведомление системных процессов о наступающем завершении работы и обеспечение
 07308	   * возможности их планирования. Для этого устанавливается сторожевой таймер, 
 07309	   * вызывающий shutdown(). В качестве аргумента передается статус завершения. 
 07310	   */
 07311	  kprintf("MINIX will now be shut down ...\n");
 07312	  tmr_arg(&shutdown_timer)->ta_int = how;
 07313	
 07314	  /* Продолжение через 1 секунду, чтобы дать процессам шанс быть запланированными и
 07315	   * выполнить завершающие действия.
 07316	   */
 07317	  set_timer(&shutdown_timer, get_uptime() + HZ, shutdown);
 07318	}
	
 07320	/*===========================================================================*
 07321	 *                              shutdown                                     *
 07322	 *===========================================================================*/
 07323	PRIVATE void shutdown(tp)
 07324	timer_t *tp;
 07325	{
 07326	/* Эта функция вызывается из prepare_shutdown или stop_sequence для завершения работы
 07327	 * MINIX. Способ завершения определяется аргументом: RBT_HALT (вернуться в монитор),
 07328	 * RBT_MONITOR (выполнить заданный код), RBT_RESET (жесткий перезапуск). 
 07329	 */
 07330	  int how = tmr_arg(tp)->ta_int;
 07331	  u16_t magic; 
 07332	
 07333	  /* Маскирование всех прерываний, включая прерывания от таймера, и остановка часов. */
 07334	  outb(INT_CTLMASK, ~0); 
 07335	  clock_stop();
 07336	
 07337	  if (mon_return && how != RBT_RESET) {
 07338	        /* Повторная инициализация контроллеров прерываний настройками BIOS по умолчанию. */
 07339	        intr_init(0);
 07340	        outb(INT_CTLMASK, 0);
 07341	        outb(INT2_CTLMASK, 0);
 07342	
 07343	        /* Возврат в монитор загрузки. Задание программы, если это еще не сделано. */
 07344	        if (how != RBT_MONITOR) phys_copy(vir2phys(""), kinfo.params_base, 1); 
 07345	        level0(monitor);
 07346	  }
 07347	
 07348	  /* Перезапуск системы путем перехода на адрес перезапуска (в реальном режиме) или
 07349	   * принудительное завершение работы процессора (защищенный режим). Установка флага 
 07350	   * мягкого перезапуска для остановки BIOS-тестирования памяти. 
 07351	   */
 07352	  magic = STOP_MEM_CHECK;
 07353	  phys_copy(vir2phys(&magic), SOFT_RESET_FLAG_ADDR, SOFT_RESET_FLAG_SIZE);
 07354	  level0(reset);
 07355	}
	




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/proc.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 07400	/* Этот файл содержит все коданды для работы с процессами и сообщениями. Совместно с файлом
 07401	 * "mpx.s" он образует нижний уровень ядра MINIX.
 07402	 * Файл proc.c имеет единственную точку входа: 
 07403	 *
 07404	 *   sys_call:         системный вызов, то есть ядро захватывается прерыванием
 07405	 *
 07406	 * Также имеется несколько точек входа из уровней прерываний и заданий: 
 07407	 *
 07408	 *   lock_notify:      уведомление процесса о системном событии
 07409	 *   lock_send:        передача события процессу
 07410	 *   lock_enqueue:     помещение процесса в одну из очередей планирования
 07411	 *   lock_dequeue:     удаление процесса из очередей планирования
 07412	 *
 07413	 * Изменения: 
 07414	 *   19 августа 2005...переписан код планирования (Jorrit N. Herder)
 07415	 *   25 июля 2005      переписана обработка системных вызовов (Jorrit N. Herder)
 07416	 *   26 мая 2005	       переписаны функции передачи сообщений (Jorrit N. Herder)
 07417	 *   24 мая 2005	       новый системный вызов уведомлений (Jorrit N. Herder)
 07418	 *   28 октября 2004	   неблокирующие вызовы приема и передачи (Jorrit N. Herder)
 07419	 *
 07420	 * Приведенный здесь код крайне важен для работы системы и влияет на ее
 07421	 * производительность. Значительную его часть составляют команды для работа со списками.
 07422	 * Для упрощения понимания и ускорения выполнения программы в коде используются 
 07423	 * указатели на указатели. Они позволяют избежать исключений для начала и конца
 07424	 * связанного списка. 
 07425	 *
 07426	 *  node_t *queue, *new_node;   // считаем глобальными переменными
 07427	 *  node_t **xpp = &queue;      // указатель на указатель на начало очереди
 07428	 *  while (*xpp != NULL)        // поиск последнего указателя в связанном списке
 07429	 *      xpp = &(*xpp)->next;    // получение указателя на следующий указатель
 07430	 *  *xpp = new_node;            // замена конца списка (NULL-указателя) 
 07431	 *  new_node->next = NULL;      // новый конец списка
 07432	 * 
 07433	 * при добавлении нового узла в конец списка обычно отдельно рассматривается особый случай
 07434	 * пустого списка, а для непустого списка ищется конец. Как показано ранее, при использовании 
 07435	 * указателей на указатели это необязательно.
 07436	 */
 07437	
 07438	#include <minix/com.h>
 07439	#include <minix/callnr.h>
 07440	#include "kernel.h"
 07441	#include "proc.h"
 07442	
 07443	/* Функции планирования и передачи сообщений, доступные другим частям ядра через
 07444	 * вызовы lock_...(). При этом прерывания временно запрещаются для предотвращения
 07445	 * условий гонок. 
 07446	 */
 07447	FORWARD _PROTOTYPE( int mini_send, (struct proc *caller_ptr, int dst,
 07448	                message *m_ptr, unsigned flags) );
 07449	FORWARD _PROTOTYPE( int mini_receive, (struct proc *caller_ptr, int src,
 07450	                message *m_ptr, unsigned flags) );
 07451	FORWARD _PROTOTYPE( int mini_notify, (struct proc *caller_ptr, int dst) );
 07452	
 07453	FORWARD _PROTOTYPE( void enqueue, (struct proc *rp) );
 07454	FORWARD _PROTOTYPE( void dequeue, (struct proc *rp) );
 07455	FORWARD _PROTOTYPE( void sched, (struct proc *rp, int *queue, int *front) );
 07456	FORWARD _PROTOTYPE( void pick_proc, (void) );
 07457	
 07458	#define BuildMess(m_ptr, src, dst_ptr) \
 07459	        (m_ptr)->m_source = (src);                                      \
 07460	        (m_ptr)->m_type = NOTIFY_FROM(src);                             \
 07461	        (m_ptr)->NOTIFY_TIMESTAMP = get_uptime();                       \
 07462	        switch (src) {                                                  \
 07463	        case HARDWARE:                                                   \
 07464	                (m_ptr)->NOTIFY_ARG = priv(dst_ptr)->s_int_pending;     \
 07465	                priv(dst_ptr)->s_int_pending = 0;                       \
 07466	                break;                                                  \
 07467	        case SYSTEM:                                                     \
 07468	                (m_ptr)->NOTIFY_ARG = priv(dst_ptr)->s_sig_pending;     \
 07469	                priv(dst_ptr)->s_sig_pending = 0;                       \
 07470	                break;                                                  \
 07471	        }
 07472	
 07473	#define CopyMess(s,sp,sm,dp,dm) \
 07474	        cp_mess(s, (sp)->p_memmap[D].mem_phys,  \
 07475	                 (vir_bytes)sm, (dp)->p_memmap[D].mem_phys, (vir_bytes)dm)
 07476	
 07477	/*===========================================================================*
 07478	 *                              sys_call                                     * 
 07479	 *===========================================================================*/
 07480	PUBLIC int sys_call(call_nr, src_dst, m_ptr)
 07481	int call_nr;                    /* номер и флаги системного вызова */
 07482	int src_dst;                    /* источник или получатель */
 07483	message *m_ptr;                 /* указатель на сообщение в пространстве источника */
 07484	{
 07485	/* Системные вызовы выполняются путем обращения к ядру с командой INT.
 07486	 * При перехвате обращения вызывается функция sys_call(), передающая и/или принимающая
 07487	 * сообщение. Вызывающий процесс всегда адресуется указателем proc_ptr.
 07488	 */
 07489	  register struct proc *caller_ptr = proc_ptr;  /* получение указателя на вызывающий процесс */
 07490	  int function = call_nr & SYSCALL_FUNC;        /* получение функции системного вызова */
 07491	  unsigned flags = call_nr & SYSCALL_FLAGS;     /* получение флагов */
 07492	  int mask_entry;                               /* бит, проверяемый в маске передачи */
 07493	  int result;                                   /* результат системного вызова */
 07494	  vir_clicks vlo, vhi;          /* виртуальные клики, содержащие сообщение для пересылки */
 07495	
 07496	  /* проверка наличия у процесса привилегий для запрошенного вызова. К ядру можно обращаться
 07497	   * только с вызовом SENDREC, поскольку задания всегда отвечают и могут не блокироваться, 
 07498	   * если вызывающий процесс не выполняет вызов receive(). 
 07499	   */
 07500	  if (! (priv(caller_ptr)->s_trap_mask & (1 << function)) || 
 07501	          (iskerneln(src_dst) && function != SENDREC
 07502	           && function != RECEIVE)) { 
 07503	      kprintf("sys_call:  trap %d not allowed, caller %d, src_dst %d\n", 
 07504	          function, proc_nr(caller_ptr), src_dst);
 07505	      return(ECALLDENIED);              /* прерывания (ловушка) запрещены маской или ядром */
 07506	  }
 07507	  
 07508	  /* Необходим допустимый адрес источника и/или приемника, если не эхо-вывод. */
 07509	  if (! (isokprocn(src_dst) || src_dst == ANY || function == ECHO)) { 
 07510	      kprintf("sys_call:  invalid src_dst, src_dst %d, caller %d\n", 
 07511	          src_dst, proc_nr(caller_ptr));
 07512	      return(EBADSRCDST);               /* недопустимый номер процесса */
 07513	  }
 07514	
 07515	  /* Если вызов использует буфер сообщений (например, SEND, RECEIVE, SENDREC, 
 07516	   * и ECHO), проверка указателя сообщения. Эта проверка позволяет располагать сообщение 
 07517	   * в пространстве данных, стека или в дыре. Проверку необходимо сделать более точной для 
 07518	   * компьютеров, где дыра не имеет отображения. 
 07519	   */
 07520	  if (function & CHECK_PTR) {   
 07521	      vlo = (vir_bytes) m_ptr >> CLICK_SHIFT;           
 07522	      vhi = ((vir_bytes) m_ptr + MESS_SIZE - 1) >> CLICK_SHIFT;
 07523	      if (vlo < caller_ptr->p_memmap[D].mem_vir || vlo > vhi ||
 07524	              vhi >= caller_ptr->p_memmap[S].mem_vir + 
 07525	              caller_ptr->p_memmap[S].mem_len) {
 07526	          kprintf("sys_call:  invalid message pointer, trap %d, caller %d\n",
 07527	                function, proc_nr(caller_ptr));
 07528	          return(EFAULT);               /* недопустимый указатель на сообщение */
 07529	      }
 07530	  }
 07531	
 07532	  /* Если выплняется вызов для передачи сообщения процессу (SEND, SENDREC или NOTIFY),
 07533	   * делается проверка разрешения передачи указанному приемнику и наличия самого
 07534	   * приемника. 
 07535	   */
 07536	  if (function & CHECK_DST) {   
 07537	      if (! get_sys_bit(priv(caller_ptr)->s_ipc_to, nr_to_id(src_dst))) {
 07538	          kprintf("sys_call:  ipc mask denied %d sending to %d\n",
 07539	                proc_nr(caller_ptr), src_dst);
 07540	          return(ECALLDENIED);          /* запрет вызова маской межпроцессного взаимодействия */
 07541	      }
 07542	
 07543	      if (isemptyn(src_dst) && !shutdown_started) {
 07544	          kprintf("sys_call:  dead dest; %d, %d, %d\n", 
 07545	              function, proc_nr(caller_ptr), src_dst);
 07546	          return(EDEADDST);             /* запрет передачи несуществующему процессу */
 07547	      }
 07548	  }
 07549	
 07550	  /* проверка принадлежности вызова к числу известных и попытка выполнить запрос. В MINIX
 07551	   * имеются следующие системные вызовы приема и передачи сообщений:
 07552	   *   - SENDREC - сочетание SEND и RECEIVE в одном системном вызове
 07553	   *   - SEND -    отправитель блокируется до тех пор, пока сообщение не будет доставлено
 07554	   *   - RECEIVE - получатель блокируется до тех пор, пока не будет доставлено допустимое сообщение
 07555	   *   - NOTIFY -  неблокирующий вызов, доставка уведомления или его пометка как активного
 07556	   *   - ECHO -    неблокирующий вызов, прямой эхо-возврат сообщения
 07557	   */
 07558	  switch(function) {
 07559	  case SENDREC: 
 07560	      /* Установка флага, чтобы сообщения не прерывали SENDREC. */
 07561	      priv(caller_ptr)->s_flags |= SENDREC_BUSY;
 07562	      /* вниз */
 07563	  case SEND:                     
 07564	      result = mini_send(caller_ptr, src_dst, m_ptr, flags);
 07565	      if (function == SEND || result != OK) {   
 07566	          break;                                /* успешное завершение или ошибка в SEND*/
 07567	      }                                         /* вниз после SENDREC */
 07568	  case RECEIVE:                  
 07569	      if (function == RECEIVE)
 07570	          priv(caller_ptr)->s_flags &= ~SENDREC_BUSY;
 07571	      result = mini_receive(caller_ptr, src_dst, m_ptr, flags);
 07572	      break;
 07573	  case NOTIFY: 
 07574	      result = mini_notify(caller_ptr, src_dst);
 07575	      break;
 07576	  case ECHO: 
 07577	      CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, caller_ptr, m_ptr);
 07578	      result = OK;
 07579	      break;
 07580	  default: 
 07581	      result = EBADCALL;                        /* недопустимый системный вызов */
 07582	  }
 07583	
 07584	  /* возврат результата системного вызова процессу. */
 07585	  return(result);
 07586	}
	
 07588	/*===========================================================================*
 07589	 *                              mini_send                                    * 
 07590	 *===========================================================================*/
 07591	PRIVATE int mini_send(caller_ptr, dst, m_ptr, flags)
 07592	register struct proc *caller_ptr;       /* кто пытается послать сообщение? */
 07593	int dst;                                /* кому предназначено сообщение? */
 07594	message *m_ptr;                         /* указатель на буфер сообщения */
 07595	unsigned flags;                         /* флаги системного вызова */
 07596	{
 07597	/* Передача сообщения от источника 'caller_ptr' приемнику 'dst'. Если 'dst' блокирован в
 07598	 * ожидании сообщения, копирование сообщения и разблокирование 'dst'. Если 'dst' не находится
 07599	 * в ожидании или ожидает сообщения от другого источника, помещение 'caller_ptr' в очередь.
 07600	 */
 07601	  register struct proc *dst_ptr = proc_addr(dst);
 07602	  register struct proc **xpp;
 07603	  register struct proc *xp;
 07604	
 07605	  /* Проверка взаимной блокировки при попытке 'caller_ptr' и 'dst' послать друг другу сообщения */
 07606	  xp = dst_ptr;
 07607	  while (xp->p_rts_flags & SENDING) {           /* проверка при передаче */
 07608	        xp = proc_addr(xp->p_sendto);           /* определение приемника xp */
 07609	        if (xp == caller_ptr) return(ELOCKED);  /* взаимная блокировка при зацикливании */
 07610	  }
 07611	
 07612	  /* Проверка, блокирован ли 'dst' при ожидании сообщения. Флаг SENDING приемника 
 07613	   * установлен, если его вызов SENDREC оказался заблокирован при передаче.  
 07614	   */
 07615	  if ( (dst_ptr->p_rts_flags & (RECEIVING | SENDING)) == RECEIVING &&
 07616	       (dst_ptr->p_getfrom == ANY || dst_ptr->p_getfrom == caller_ptr->p_nr)) {
 07617	        /* Приемник ждет этого сообщения. */
 07618	        CopyMess(caller_ptr->p_nr, caller_ptr, m_ptr, dst_ptr,
 07619	                 dst_ptr->p_messbuf);
 07620	        if ((dst_ptr->p_rts_flags &= ~RECEIVING) == 0) enqueue(dst_ptr);
 07621	  } else if ( ! (flags & NON_BLOCKING)) {
 07622	        /* Приемник не ждет. Блокирование и исключение вызывающего процесса из очереди. */
 07623	        caller_ptr->p_messbuf = m_ptr;
 07624	        if (caller_ptr->p_rts_flags == 0) dequeue(caller_ptr);
 07625	        caller_ptr->p_rts_flags |= SENDING;
 07626	        caller_ptr->p_sendto = dst;
 07627	
 07628	        /* Теперь процесс блокирован. Помещение его в очередь приемника. */
 07629	        xpp = &dst_ptr->p_caller_q;             /* поиск конца списка */
 07630	        while (*xpp != NIL_PROC) xpp = &(*xpp)->p_q_link;       
 07631	        *xpp = caller_ptr;                      /* добавление вызывающего процесса в конец*/
 07632	        caller_ptr->p_q_link = NIL_PROC;        /* пометка нового конца списка */
 07633	  } else {
 07634	        return(ENOTREADY);
 07635	  }
 07636	  return(OK);
 07637	}
	
 07639	/*===========================================================================*
 07640	 *                              mini_receive                                 * 
 07641	 *===========================================================================*/
 07642	PRIVATE int mini_receive(caller_ptr, src, m_ptr, flags)
 07643	register struct proc *caller_ptr;       /* процесс, пытающийся послать сообщение */
 07644	int src;                                /* нужный источник сообщения */
 07645	message *m_ptr;                         /* указатель на буфер сообщения */
 07646	unsigned flags;                         /* флаги системного вызова */
 07647	{
 07648	/* Процесс или задача собирается получить сообщение. Если сообщение уже находится в очереди,
 07649	 * получение сообщения и разблокирование источника. Если сообщения от желаемого источника
 07650	 * нет, блокировать вызывающий процесс (при условии, что не установлены флаги, запрещающие блокирование).  
 07651	 */
 07652	  register struct proc **xpp;
 07653	  register struct notification **ntf_q_pp;
 07654	  message m;
 07655	  int bit_nr;
 07656	  sys_map_t *map;
 07657	  bitchunk_t *chunk;
 07658	  int i, src_id, src_proc_nr;
 07659	
 07660	  /* Проверка доступности сообщения от желаемого источника.
 07661	   * Флаг SENDING вызывающего процесса установлен, если передача с помощью SENDREC не 
 07662	   * удалась. В этом случае процесс следует заблокировать.
 07663	   */
 07664	  if (!(caller_ptr->p_rts_flags & SENDING)) {
 07665	
 07666	    /* Проверка наличия активных уведомлений, за исключением SENDREC. */
 07667	    if (! (priv(caller_ptr)->s_flags & SENDREC_BUSY)) {
 07668	
 07669	        map = &priv(caller_ptr)->s_notify_pending;
 07670	        for (chunk=&map->chunk[0]; chunk<&map->chunk[NR_SYS_CHUNKS]; chunk++) {
 07671	
 07672	            /* Поиск активного уведомления от требуемого источника. */ 
 07673	            if (! *chunk) continue;                     /* биты в chunk не установлены*/
 07674	            for (i=0; ! (*chunk & (1<<i)); ++i) {}      /* поиск бита */
 07675	            src_id = (chunk - &map->chunk[0]) * BITCHUNK_BITS + i;
 07676	            if (src_id >= NR_SYS_PROCS) break;          /* вне диапазона */
 07677	            src_proc_nr = id_to_nr(src_id);             /* получение номера процесса источника */
 07678	            if (src!=ANY && src!=src_proc_nr) continue; /* некорректный источник */
 07679	            *chunk &= ~(1 << i);                        /* снятие активности */
 07680	
 07681	            /* Источник найден, доставка уведомления. */
 07682	            BuildMess(&m, src_proc_nr, caller_ptr);     /* сборка сообщения */
 07683	            CopyMess(src_proc_nr, proc_addr(HARDWARE), &m, caller_ptr, m_ptr);
 07684	            return(OK);                                 /* возврат кода удачного завершения */
 07685	        }
 07686	    }
 07687	
 07688	    /* Проверка очереди вызывающего процесса. Использование указателей на указатели для простоты кода. */
 07689	    xpp = &caller_ptr->p_caller_q;
 07690	    while (*xpp != NIL_PROC) {
 07691	        if (src == ANY || src == proc_nr(*xpp)) {
 07692	            /* Найдено корректное сообщение. Его копирование и обновление состояния. */
 07693	            CopyMess((*xpp)->p_nr, *xpp, (*xpp)->p_messbuf, caller_ptr, m_ptr);
 07694	            if (((*xpp)->p_rts_flags &= ~SENDING) == 0) enqueue(*xpp);
 07695	            *xpp = (*xpp)->p_q_link;            /* удаление из очереди */
 07696	            return(OK);                         /* возврат кода удачного завершения */
 07697	        }
 07698	        xpp = &(*xpp)->p_q_link;                /* переход к следующему элементу очереди */
 07699	    }
 07700	  }
 07701	
 07702	  /* Допустимое сообщение не найдено, либо вызывающий процесс не смог осуществить передачу с помощью 
 07703	   * SENDREC. Блокирование процесса, ожидающего сообщение, если флаги не указывают иначе.
 07704	   */
 07705	  if ( ! (flags & NON_BLOCKING)) {
 07706	      caller_ptr->p_getfrom = src;              
 07707	      caller_ptr->p_messbuf = m_ptr;
 07708	      if (caller_ptr->p_rts_flags == 0) dequeue(caller_ptr);
 07709	      caller_ptr->p_rts_flags |= RECEIVING;             
 07710	      return(OK);
 07711	  } else {
 07712	      return(ENOTREADY);
 07713	  }
 07714	}
	
 07716	/*===========================================================================*
 07717	 *                              mini_notify                                  * 
 07718	 *===========================================================================*/
 07719	PRIVATE int mini_notify(caller_ptr, dst)
 07720	register struct proc *caller_ptr;       /* источник уведомления */
 07721	int dst;                                /* приемник уведомления */
 07722	{
 07723	  register struct proc *dst_ptr = proc_addr(dst);
 07724	  int src_id;                           /* идентификатор источника для отложенной доставки */
 07725	  message m;                            /* уведомление */ 07726	
 07727	  /* Проверка, блокирован ли приемник этого сообщения. Процесс может выполнять передачу и
 07728	   * прием с помощью системного вызова SENDREC.
 07729	   */
 07730	  if ((dst_ptr->p_rts_flags & (RECEIVING|SENDING)) == RECEIVING &&
 07731	      ! (priv(dst_ptr)->s_flags & SENDREC_BUSY) &&
 07732	      (dst_ptr->p_getfrom == ANY || dst_ptr->p_getfrom == caller_ptr->p_nr)) {
 07733	
 07734	      /* Приемник ожидает сообщения: сборка и доставка уведомления. Копирование осуществляется
 07735	       * из псевдоисточника HARDWARE, так как сообщение находится в адресном пространстве
 07736	       * ядра.
 07737	       */ 
 07738	      BuildMess(&m, proc_nr(caller_ptr), dst_ptr);
 07739	      CopyMess(proc_nr(caller_ptr), proc_addr(HARDWARE), &m, 
 07740	          dst_ptr, dst_ptr->p_messbuf);
 07741	      dst_ptr->p_rts_flags &= ~RECEIVING;       /* разблокирование приемника */
 07742	      if (dst_ptr->p_rts_flags == 0) enqueue(dst_ptr);
 07743	      return(OK);
 07744	  } 
 07745	
 07746	  /* Приемник не готов к получению уведомления: уведомление становится активным и помечается
 07747	   * в битовой карте. Обратите внимание на косвенность: в битовой карте активных уведомлений
 07748	   * указан идентификатор системы, а не номер процесса.
 07749	   */ 
 07750	  src_id = priv(caller_ptr)->s_id;
 07751	  set_sys_bit(priv(dst_ptr)->s_notify_pending, src_id); 
 07752	  return(OK);
 07753	}
	
 07755	/*===========================================================================*
 07756	 *                              lock_notify                                  *
 07757	 *===========================================================================*/
 07758	PUBLIC int lock_notify(src, dst)
 07759	int src;                        /* отправитель уведомления */
 07760	int dst;                        /* получатель уведомления */
 07761	{
 07762	/* Безопасный вход в функцию mini_notify() для заданий и обработчиков прерываний. Отправитель
 07763	 * указан явно, чтобы не не перепутать источник вызова. Ядро MINIX не допускает повторного входа,
 07764	 * то есть прерывания запрещаются после первого входа в ядро (по причине аппаратного 
 07765	 * прерывания, ловушки или исключения). Блокирование осуществляется временным запрещением
 07766	 * прерываний. 
 07767	 */
 07768	  int result;
 07769	
 07770	  /* Исключение или прерывание уже произошло, поэтому блокировка установлена. */
 07771	  if (k_reenter >= 0) {
 07772	      result = mini_notify(proc_addr(src), dst); 
 07773	  }
 07774	
 07775	  /* Вызов из уровня задания, требуется блокировка. */
 07776	  else {
 07777	      lock(0, "notify");
 07778	      result = mini_notify(proc_addr(src), dst); 
 07779	      unlock(0);
 07780	  }
 07781	  return(result);
 07782	}
	
 07784	/*===========================================================================*
 07785	 *                              enqueue                                      * 
 07786	 *===========================================================================*/
 07787	PRIVATE void enqueue(rp)
 07788	register struct proc *rp;       /* этот процесс теперь может быть запущен */
 07789	{
 07790	/* Добавление 'rp' в одну из очередей готовых для запуска процессов. Эта
 07791	 * функция ответственна за постановку процесса в очередь. Механизм  
 07792	 * постановки реализован в ней, а политика определена в sched() и
 07793	 * pick_proc().
 07794	 */
 07795	  int q;                                        /* используемая очередь планирования */
 07796	  int front;                                    /* добавление в начало или конец */
 07797	
 07798	  /* Определение местоположения для процесса в очереди */
 07799	  sched(rp, &q, &front);
 07800	
 07801	  /* Добавление процесса в очередь. */
 07802	  if (rdy_head[q] == NIL_PROC) {                /* добавление в пустую очередь */
 07803	      rdy_head[q] = rdy_tail[q] = rp;           /* создание новой очереди */
 07804	      rp->p_nextready = NIL_PROC;               /* пометка нового конца */
 07805	  } 
 07806	  else if (front) {                             /* добавление в начало очереди */
 07807	      rp->p_nextready = rdy_head[q];            /* присоединение начала к очереди */
 07808	      rdy_head[q] = rp;                         /* задание нового начала */
 07809	  } 
 07810	  else {                                        /* добавление в конец очереди */
 07811	      rdy_tail[q]->p_nextready = rp;            /* присоединение конца к очереди */       
 07812	      rdy_tail[q] = rp;                         /* задание нового конца */
 07813	      rp->p_nextready = NIL_PROC;               /* пометка нового конца */
 07814	  }
 07815	
 07816	  /* Выбор следующего процесса для выполнения. */
 07817	  pick_proc();                  
 07818	}
	
 07820	/*===========================================================================*
 07821	 *                              dequeue                                      * 
 07822	 *===========================================================================*/
 07823	PRIVATE void dequeue(rp)
 07824	register struct proc *rp;       /* этот процесс больше не может выполняться */
 07825	{
 07826	/* Процесс должен быть удален из очереди планирования, например, из-за блокирования.
 07827	 * Если удаляется активный процесс, новый процесс выбирается для выполнения вызовом
 07828	 * pick_proc().
 07829	 */
 07830	  register int q = rp->p_priority;              /* используемая очередь */
 07831	  register struct proc **xpp;                   /* проход очереди */
 07832	  register struct proc *prev_xp;
 07833	
 07834	  /* Побочный эффект для ядра: проверка переполнения стека задания */
 07835	  if (iskernelp(rp)) {                          
 07836	        if (*priv(rp)->s_stack_guard != STACK_GUARD)
 07837	                panic("stack overrun by task", proc_nr(rp));
 07838	  }
 07839	
 07840	  /* Теперь нужно гарантировать, что процесс не находится в очереди. Если он обнаруживается,
 07841	   * то подлежит удалению. Если процесс не выполняется, ему можно послать сигнал, который 
 07842	   * уничтожит его.
 07843	   */
 07844	  prev_xp = NIL_PROC;                           
 07845	  for (xpp = &rdy_head[q]; *xpp != NIL_PROC; xpp = &(*xpp)->p_nextready) {
 07846	
 07847	      if (*xpp == rp) {                         /* найден процесс для удаления */
 07848	          *xpp = (*xpp)->p_nextready;           /* заменить следующей цепочкой */
 07849	          if (rp == rdy_tail[q])                /* удаление конца очереди */
 07850	              rdy_tail[q] = prev_xp;            /* задание нового конца */
 07851	          if (rp == proc_ptr || rp == next_ptr) /* удаление активного процесса */
 07852	              pick_proc();                      /* выбор нового процесса для выполнения */
 07853	          break;
 07854	      }
 07855	      prev_xp = *xpp;                           /* сохранение предыдущего процесса в цепочке */
 07856	  }
 07857	}
	
 07859	/*===========================================================================*
 07860	 *                              sched                                        * 
 07861	 *===========================================================================*/
 07862	PRIVATE void sched(rp, queue, front)
 07863	register struct proc *rp;                       /* планируемый процесс */
 07864	int *queue;                                     /* возврат:  очередь для размещения */
 07865	int *front;                                     /* возврат:  начало или конец */
 07866	{
 07867	/* Эта функция определяет политику планирования. Она вызывается, чтобы определить
 07868	 * очередь, в которую нужно поставить процесс. Побочный эффект: приоритет процесса
 07869	 * может изменяться.
 07870	 */
 07871	  static struct proc *prev_ptr = NIL_PROC;      /* предыдущий без времени */
 07872	  int time_left = (rp->p_ticks_left > 0);       /* квант полностью израсходован */
 07873	  int penalty = 0;                              /* изменение приоритета */
 07874	
 07875	  /* Проверка наличия неизрасходованного времени у процесса. При его отсутствии выделение 
 07876	   * еще одного кванта и, возможно, повышение приоритета. Приоритет процессов, использующих
 07877	   * несколько квантов подряд, понижается, чтобы избежать бесконечного зацикливания 
 07878	   * высокоприоритетных процессов (системных серверов и драйверов). 
 07879	   */
 07880	  if ( ! time_left) {                           /* израсходован ли квант? */
 07881	      rp->p_ticks_left = rp->p_quantum_size;    /* выделение нового кванта */
 07882	      if (prev_ptr == rp) penalty ++;           /* перехват бесконечного цикла */
 07883	      else penalty --;                          /* медленный откат */
 07884	      prev_ptr = rp;                            /* сохранение указателя для след. процесса */
 07885	  }
 07886	
 07887	  /* Определение нового приоритета данного процесса. Диапазон возможных приоритетов лежит 
 07888	   * между приоритетом процесса IDLE и максимальным приоритетом данного процесса. Задания 
 07889	   * ядра и процесс IDLE всегда имеют неизменный приоритет.
 07890	   */
 07891	  if (penalty != 0 && ! iskernelp(rp)) {
 07892	      rp->p_priority += penalty;                /* обновление приоритета */
 07893	      if (rp->p_priority < rp->p_max_priority)  /* проверка верхней границы */ 
 07894	          rp->p_priority=rp->p_max_priority;
 07895	      else if (rp->p_priority > IDLE_Q-1)       /* проверка нижней границы */
 07896	          rp->p_priority = IDLE_Q-1;
 07897	  }
 07898	
 07899	  /* Если квант не израсходован, процесс добавляется в начало своей очереди, чтобы
 07900	   * немедленно запуститься. Процесс всегда помещается в очередь, соответствующую своему
 07901	   * текущему приоритету. 
 07902	   */
 07903	  *queue = rp->p_priority;
 07904	  *front = time_left;
 07905	}
	
 07907	/*===========================================================================*
 07908	 *                              pick_proc                                    * 
 07909	 *===========================================================================*/
 07910	PRIVATE void pick_proc()
 07911	{
 07912	/* Выбор следующего процесса для выполнения. Новый процесс выбирается установкой указателя
 07913	 * 'next_ptr'. Если выбирается процесс, которому начисляется системное время, он
 07914	 * регистрируется в указателе 'bill_ptr', чтобы таймерное задание могло вести начисление.
 07915	 */
 07916	  register struct proc *rp;                     /* процесс для выполнения */
 07917	  int q;                                        /* проход по очередям */
 07918	
 07919	  /* Проверка каждой очереди на наличие готовых процессов. Число очередей задано в файле
 07920	   * proc.h, а приоритеты — в таблице образа. Самая низкоприоритетная очередь содержит
 07921	   * процесс IDLE, всегда готовый к выполнению.
 07922	   */
 07923	  for (q=0; q < NR_SCHED_QUEUES; q++) { 
 07924	      if ( (rp = rdy_head[q]) != NIL_PROC) {
 07925	          next_ptr = rp;                        /* следующим выполнить процесс 'rp' */
 07926	          if (priv(rp)->s_flags & BILLABLE)             
 07927	              bill_ptr = rp;                    /* начисление системного времени */
 07928	          return;                                
 07929	      }
 07930	  }
 07931	}
	
 07933	/*===========================================================================*
 07934	 *                              lock_send                                    *
 07935	 *===========================================================================*/
 07936	PUBLIC int lock_send(dst, m_ptr)
 07937	int dst;                        /* приемник сообщения */
 07938	message *m_ptr;                 /* указатель на буфер сообщений */
 07939	{
 07940	/* Безопасный вход в функцию mini_send() для заданий. */
 07941	  int result;
 07942	  lock(2, "send");
 07943	  result = mini_send(proc_ptr, dst, m_ptr, NON_BLOCKING);
 07944	  unlock(2);
 07945	  return(result);
 07946	}
	
 07948	/*===========================================================================*
 07949	 *                              lock_enqueue                                 *
 07950	 *===========================================================================*/
 07951	PUBLIC void lock_enqueue(rp)
 07952	struct proc *rp;                /* теперь этот процесс может быть запущен */
 07953	{
 07954	/* Безопасный вход в функцию enqueue() для заданий. */
 07955	  lock(3, "enqueue");
 07956	  enqueue(rp);
 07957	  unlock(3);
 07958	}
	
 07960	/*===========================================================================*
 07961	 *                              lock_dequeue                                 *
 07962	 *===========================================================================*/
 07963	PUBLIC void lock_dequeue(rp)
 07964	struct proc *rp;                /* этот процесс больше не может быть запущен */
 07965	{
 07966	/* Безопасный вход в функцию dequeue() для заданий. */
 07967	  lock(4, "dequeue");
 07968	  dequeue(rp);
 07969	  unlock(4);
 07970	}
	





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/exception.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 08000	/* Этот файл содержит простой обработчик исключений. Исключения в пользовательских
 08001	 * процессах преобразуются в сигналы, а исключения в задании ядра приводят к сбою
 08002	 * системы.
 08003	 */
 08004	
 08005	#include "kernel.h"
 08006	#include <signal.h>
 08007	#include "proc.h"
 08008	
 08009	/*===========================================================================*
 08010	 *                              exception                                    *
 08011	 *===========================================================================*/
 08012	PUBLIC void exception(vec_nr)
 08013	unsigned vec_nr;
 08014	{
 08015	/* Произошло исключение или неожиданное прерывание. */
 08016	
 08017	  struct ex_s {
 08018	        char *msg;
 08019	        int signum;
 08020	        int minprocessor;
 08021	  };
 08022	  static struct ex_s ex_data[] = {
 08023	        { "Divide error", SIGFPE, 86 },
 08024	        { "Debug exception", SIGTRAP, 86 },
 08025	        { "Nonmaskable interrupt", SIGBUS, 86 },
 08026	        { "Breakpoint", SIGEMT, 86 },
 08027	        { "Overflow", SIGFPE, 86 },
 08028	        { "Bounds check", SIGFPE, 186 },
 08029	        { "Invalid opcode", SIGILL, 186 },
 08030	        { "Coprocessor not available", SIGFPE, 186 },
 08031	        { "Double fault", SIGBUS, 286 },
 08032	        { "Copressor segment overrun", SIGSEGV, 286 },
 08033	        { "Invalid TSS", SIGSEGV, 286 },
 08034	        { "Segment not present", SIGSEGV, 286 },
 08035	        { "Stack exception", SIGSEGV, 286 },    /* STACK_FAULT уже используется */
 08036	        { "General protection", SIGSEGV, 286 },
 08037	        { "Page fault", SIGSEGV, 386 },         /* не близко */
 08038	        { NIL_PTR, SIGILL, 0 },                 /* возможно программная ловушка */
 08039	        { "Coprocessor error", SIGFPE, 386 },
 08040	  };
 08041	  register struct ex_s *ep;
 08042	  struct proc *saved_proc;
 08043	
 08044	  /* Сохранение указателя proc_ptr, поскольку его значение может измениться при отладке. */
 08045	  saved_proc = proc_ptr;        
 08046	
 08047	  ep = &ex_data[vec_nr];
 08048	
 08049	  if (vec_nr == 2) {            /* ложный идентификатор NMI на некоторых компьютерах */
 08050	        kprintf("got spurious NMI\n");
 08051	        return;
 08052	  }
 08053	
 08054	  /* Если исключение происходит при выполнении процесса, переменная k_reenter равна 0.
 08055	   * Исключения в обработчиках прерываний и системных ловушках делают значение k_reenter
 08056	   * положительным.
 08057	   */
 08058	  if (k_reenter == 0 && ! iskernelp(saved_proc)) {
 08059	        cause_sig(proc_nr(saved_proc), ep->signum);
 08060	        return;
 08061	  }
 08062	
 08063	  /* Исключение в системном коде. Этого не должно происходить. */
 08064	  if (ep->msg == NIL_PTR || machine.processor < ep->minprocessor)
 08065	        kprintf("\nIntel-reserved exception %d\n", vec_nr);
 08066	  else
 08067	        kprintf("\n%s\n", ep->msg);
 08068	  kprintf("k_reenter = %d ", k_reenter);
 08069	  kprintf("process %d (%s), ", proc_nr(saved_proc), saved_proc->p_name);
 08070	  kprintf("pc = %u: 0x%x", (unsigned) saved_proc->p_reg.cs,
 08071	  (unsigned) saved_proc->p_reg.pc);
 08072	
 08073	  panic("exception in a kernel task", NO_NUM);
 08074	}
	





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/i8259.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 08100	/* Этот файл содержит подпрограммы инициализации контроллера прерываний 8259: 
 08101	 *      put_irq_handler - регистрация обработчика преываний
 08102	 *      rm_irq_handler -  удаление обработчика прерываний
 08103	 *      intr_handle -     обработка аппаратного прерывания
 08104	 *      intr_init -       инициализация контроллера (-ов) прерываний 
 08105	 */
 08106	
 08107	#include "kernel.h"
 08108	#include "proc.h"
 08109	#include <minix/com.h>
 08110	
 08111	#define ICW1_AT         0x11    /* срабатывание по фронту, каскад, требуется ICW4 */
 08112	#define ICW1_PC         0x13    /* срабатывание по фронту, нет каскада, требуется ICW4 */
 08113	#define ICW1_PS         0x19    /* срабатывание по уровню, каскад, требуется ICW4 */
 08114	#define ICW4_AT_SLAVE   0x01    /* нет SFNM, нет буферизации, обычное завершение, 8086 */
 08115	#define ICW4_AT_MASTER  0x05    /* нет SFNM, нет буферизации, обычное завершение, 8086 */
 08116	#define ICW4_PC_SLAVE   0x09    /* нет SFNM, буферизация, обычное завершение, 8086 */
 08117	#define ICW4_PC_MASTER  0x0D    /* нет SFNM, буферизация, обычное завершение, 8086 */
 08118	
 08119	#define set_vec(nr, addr)       ((void)0)
 08120	
 08121	/*===========================================================================*
 08122	 *                              intr_init                                    *
 08123	 *===========================================================================*/
 08124	PUBLIC void intr_init(mine)
 08125	int mine;
 08126	{
 08127	/* Инициализация 8259, после которой все прерывания запрещены. Это делается только в
 08128	 * защищенном режиме; в реальном режиме вместо 8259 мы используем BIOS. Флаг "mine"
 08129	 * устанавливается, если контроллеры 8259 требуется запрограммировать под MINIX или
 08130	 * сбросить в значения, ожидаемые BIOS.
 08131	 */
 08132	  int i;
 08133	
 08134	  intr_disable();
 08135	
 08136	      /* AT и более новые PS/2 имеют два контроллера прерываний (главный и подчиненный)
 08137	       * на IRQ 2. (нам не нужно иметь дело с компьютером, у которого один контроллер,
 08138	       * поскольку он должен работать в защищенном режиме.)
 08139	       */
 08140	      outb(INT_CTL, machine.ps_mca ? ICW1_PS :  ICW1_AT);
 08141	      outb(INT_CTLMASK, mine ? IRQ0_VECTOR :  BIOS_IRQ0_VEC);
 08142	                                                        /* ICW2 для главного */
 08143	      outb(INT_CTLMASK, (1 << CASCADE_IRQ));            /* ICW3 указывает подчиненных */
 08144	      outb(INT_CTLMASK, ICW4_AT_MASTER);
 08145	      outb(INT_CTLMASK, ~(1 << CASCADE_IRQ));           /* маска IRQ 0-7 */
 08146	      outb(INT2_CTL, machine.ps_mca ? ICW1_PS :  ICW1_AT);
 08147	      outb(INT2_CTLMASK, mine ? IRQ8_VECTOR :  BIOS_IRQ8_VEC);
 08148	                                                        /* ICW2 для подчиненного */
 08149	      outb(INT2_CTLMASK, CASCADE_IRQ);                  /* ICW3 - номер подчиненного */
 08150	      outb(INT2_CTLMASK, ICW4_AT_SLAVE);
 08151	      outb(INT2_CTLMASK, ~0);                           /* маска IRQ 8-15 */
 08152	
 08153	      /* копирование векторов BIOS из BIOS в Minix location, чтобы обеспечить возможность
 08154	       * вызовов BIOS без перепрограммирования контроллеров i8259.
 08155	       */
 08156	      phys_copy(BIOS_VECTOR(0) * 4L, VECTOR(0) * 4L, 8 * 4L);
 08157	}
	
 08159	/*===========================================================================*
 08160	 *                              put_irq_handler                              *
 08161	 *===========================================================================*/
 08162	PUBLIC void put_irq_handler(hook, irq, handler)
 08163	irq_hook_t *hook;
 08164	int irq;
 08165	irq_handler_t handler;
 08166	{
 08167	/* регистрация обработчика прерывания. */
 08168	  int id;
 08169	  irq_hook_t **line;
 08170	
 08171	  if (irq < 0 || irq >= NR_IRQ_VECTORS)
 08172	      panic("invalid call to put_irq_handler", irq);
 08173	
 08174	  line = &irq_handlers[irq];
 08175	  id = 1;
 08176	  while (*line != NULL) {
 08177	      if (hook == *line) return;        /* дополнительная инициализация */
 08178	      line = &(*line)->next;
 08179	      id <<= 1;
 08180	  }
 08181	  if (id == 0) panic("Too many handlers for irq", irq);
 08182	
 08183	  hook->next = NULL;
 08184	  hook->handler = handler;
 08185	  hook->irq = irq;
 08186	  hook->id = id;
 08187	  *line = hook;
 08188	
 08189	  irq_use |= 1 << irq;
 08190	}
	
 08192	/*===========================================================================*
 08193	 *                              rm_irq_handler                               *
 08194	 *===========================================================================*/
 08195	PUBLIC void rm_irq_handler(hook)
 08196	irq_hook_t *hook;
 08197	{
 08198	/* удаление обработчика прерываний. */
 08199	  int irq = hook->irq; 
 08200	  int id = hook->id;
 08201	  irq_hook_t **line;
 08202	
 08203	  if (irq < 0 || irq >= NR_IRQ_VECTORS) 
 08204	      panic("invalid call to rm_irq_handler", irq);
 08205	
 08206	  line = &irq_handlers[irq];
 08207	  while (*line != NULL) {
 08208	      if ((*line)->id == id) {
 08209	          (*line) = (*line)->next;
 08210	          if (! irq_handlers[irq]) irq_use &= ~(1 << irq);
 08211	          return;
 08212	      }
 08213	      line = &(*line)->next;
 08214	  }
 08215	  /* При отсутствии обработчика управление должно быть передано сюда. */
 08216	}
	
 08218	/*===========================================================================*
 08219	 *                              intr_handle                                  *
 08220	 *===========================================================================*/
 08221	PUBLIC void intr_handle(hook)
 08222	irq_hook_t *hook;
 08223	{
 08224	/* Вызов обработчиков прерывания по заданному списку.
 08225	 * Ассемблерная часть обработчика уже маскировала прерывание, включила контроллеры и
 08226	 * разрешила прерывания.
 08227	 */
 08228	
 08229	  /* Вызовы списка обработчиков IRQ. */
 08230	  while (hook != NULL) {
 08231	      /* Каждый обработчик списка помечается активным путем установки бита ID, далее
 08232	       * вызывается функция, а затем пометка активности снимается, если функция возвращает true.
 08233	       */
 08234	      irq_actids[hook->irq] |= hook->id;
 08235	      if ((*hook->handler)(hook)) irq_actids[hook->irq] &= ~hook->id;
 08236	      hook = hook->next;
 08237	  }
 08238	
 08239	  /* Теперь ассемблерный код запретит прерывания, демаскирует IRQ если и только если
 08240	   * все ID-биты сброшены, а затем перезапустит процесс.
 08241	   */
 08242	}



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/protect.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 08300	/* Этот файл содержит код инициализации защищенного режима, инициализирующий дескрипторы
 08301	 * сегментов кода и данных, глобальные дескрипторы для локальных дескрипторов в таблице
 08302	 * процессов.
 08303	 */
 08304	
 08305	#include "kernel.h"
 08306	#include "proc.h"
 08307	#include "protect.h"
 08308	
 08309	#define INT_GATE_TYPE   (INT_286_GATE | DESC_386_BIT)
 08310	#define TSS_TYPE        (AVL_286_TSS  | DESC_386_BIT)
 08311	
 08312	struct desctableptr_s {
 08313	  char limit[sizeof(u16_t)];
 08314	  char base[sizeof(u32_t)];             /* u24_t + pad для 286 */
 08315	};
 08316	
 08317	struct gatedesc_s {
 08318	  u16_t offset_low;
 08319	  u16_t selector;
 08320	  u8_t pad;                     /* |000|XXXXX| ig & trpg, |XXXXXXXX| task g */
 08321	  u8_t p_dpl_type;              /* |P|DL|0|TYPE| */
 08322	  u16_t offset_high;
 08323	};
 08324	
 08325	struct tss_s {
 08326	  reg_t backlink;
 08327	  reg_t sp0;                    /* указатель стека, используемый во время прерывания */
 08328	  reg_t ss0;                    /*   "   сегмент  "  "    "        "     */
 08329	  reg_t sp1;
 08330	  reg_t ss1;
 08331	  reg_t sp2;
 08332	  reg_t ss2;
 08333	  reg_t cr3;
 08334	  reg_t ip;
 08335	  reg_t flags;
 08336	  reg_t ax;
 08337	  reg_t cx;
 08338	  reg_t dx;
 08339	  reg_t bx;
 08340	  reg_t sp;
 08341	  reg_t bp;
 08342	  reg_t si;
 08343	  reg_t di;
 08344	  reg_t es;
 08345	  reg_t cs;
 08346	  reg_t ss;
 08347	  reg_t ds;
 08348	  reg_t fs;
 08349	  reg_t gs;
 08350	  reg_t ldt;
 08351	  u16_t trap;
 08352	  u16_t iobase;
 08353	/* u8_t iomap[0]; */
 08354	};
 08355	
 08356	PUBLIC struct segdesc_s gdt[GDT_SIZE];          /* используется в klib.s и mpx.s */
 08357	PRIVATE struct gatedesc_s idt[IDT_SIZE];        /* инициализация нулями */
 08358	PUBLIC struct tss_s tss;                        /* инициализация нулями */
 08359	
 08360	FORWARD _PROTOTYPE( void int_gate, (unsigned vec_nr, vir_bytes offset,
 08361	                unsigned dpl_type) );
 08362	FORWARD _PROTOTYPE( void sdesc, (struct segdesc_s *segdp, phys_bytes base,
 08363	                vir_bytes size) );
 08364	
 08365	/*===========================================================================*
 08366	 *                              prot_init                                    *
 08367	 *===========================================================================*/
 08368	PUBLIC void prot_init()
 08369	{
 08370	/* Установка таблиц для защищенного режима.
 08371	 * Все записи глобальной таблицы дескрипторов выделяются на этапе компиляции.
 08372	 */
 08373	  struct gate_table_s *gtp;
 08374	  struct desctableptr_s *dtp;
 08375	  unsigned ldt_index;
 08376	  register struct proc *rp;
 08377	
 08378	  static struct gate_table_s {
 08379	        _PROTOTYPE( void (*gate), (void) );
 08380	        unsigned char vec_nr;
 08381	        unsigned char privilege;
 08382	  }
 08383	  gate_table[] = {
 08384	        { divide_error, DIVIDE_VECTOR, INTR_PRIVILEGE },
 08385	        { single_step_exception, DEBUG_VECTOR, INTR_PRIVILEGE },
 08386	        { nmi, NMI_VECTOR, INTR_PRIVILEGE },
 08387	        { breakpoint_exception, BREAKPOINT_VECTOR, USER_PRIVILEGE },
 08388	        { overflow, OVERFLOW_VECTOR, USER_PRIVILEGE },
 08389	        { bounds_check, BOUNDS_VECTOR, INTR_PRIVILEGE },
 08390	        { inval_opcode, INVAL_OP_VECTOR, INTR_PRIVILEGE },
 08391	        { copr_not_available, COPROC_NOT_VECTOR, INTR_PRIVILEGE },
 08392	        { double_fault, DOUBLE_FAULT_VECTOR, INTR_PRIVILEGE },
 08393	        { copr_seg_overrun, COPROC_SEG_VECTOR, INTR_PRIVILEGE },
 08394	        { inval_tss, INVAL_TSS_VECTOR, INTR_PRIVILEGE },
 08395	        { segment_not_present, SEG_NOT_VECTOR, INTR_PRIVILEGE },
 08396	        { stack_exception, STACK_FAULT_VECTOR, INTR_PRIVILEGE },
 08397	        { general_protection, PROTECTION_VECTOR, INTR_PRIVILEGE },
 08398	        { page_fault, PAGE_FAULT_VECTOR, INTR_PRIVILEGE },
 08399	        { copr_error, COPROC_ERR_VECTOR, INTR_PRIVILEGE },
 08400	        { hwint00, VECTOR( 0), INTR_PRIVILEGE },
 08401	        { hwint01, VECTOR( 1), INTR_PRIVILEGE },
 08402	        { hwint02, VECTOR( 2), INTR_PRIVILEGE },
 08403	        { hwint03, VECTOR( 3), INTR_PRIVILEGE },
 08404	        { hwint04, VECTOR( 4), INTR_PRIVILEGE },
 08405	        { hwint05, VECTOR( 5), INTR_PRIVILEGE },
 08406	        { hwint06, VECTOR( 6), INTR_PRIVILEGE },
 08407	        { hwint07, VECTOR( 7), INTR_PRIVILEGE },
 08408	        { hwint08, VECTOR( 8), INTR_PRIVILEGE },
 08409	        { hwint09, VECTOR( 9), INTR_PRIVILEGE },
 08410	        { hwint10, VECTOR(10), INTR_PRIVILEGE },
 08411	        { hwint11, VECTOR(11), INTR_PRIVILEGE },
 08412	        { hwint12, VECTOR(12), INTR_PRIVILEGE },
 08413	        { hwint13, VECTOR(13), INTR_PRIVILEGE },
 08414	        { hwint14, VECTOR(14), INTR_PRIVILEGE },
 08415	        { hwint15, VECTOR(15), INTR_PRIVILEGE },
 08416	        { s_call, SYS386_VECTOR, USER_PRIVILEGE },      /* системный вызов 386 */
 08417	        { level0_call, LEVEL0_VECTOR, TASK_PRIVILEGE },
 08418	  };
 08419	
 08420	  /* Создание указателей gdt и idt в GDT там, где ожидает BIOS. */
 08421	  dtp= (struct desctableptr_s *) &gdt[GDT_INDEX];
 08422	  * (u16_t *) dtp->limit = (sizeof gdt) - 1;
 08423	  * (u32_t *) dtp->base = vir2phys(gdt);
 08424	
 08425	  dtp= (struct desctableptr_s *) &gdt[IDT_INDEX];
 08426	  * (u16_t *) dtp->limit = (sizeof idt) - 1;
 08427	  * (u32_t *) dtp->base = vir2phys(idt);
 08428	
 08429	  /* Создание дескрипторов сегментов для заданий и обработчиков прерываний. */
 08430	  init_codeseg(&gdt[CS_INDEX],
 08431	         kinfo.code_base, kinfo.code_size, INTR_PRIVILEGE);
 08432	  init_dataseg(&gdt[DS_INDEX],
 08433	         kinfo.data_base, kinfo.data_size, INTR_PRIVILEGE);
 08434	  init_dataseg(&gdt[ES_INDEX], 0L, 0, TASK_PRIVILEGE);
 08435	
 08436	  /* Создание начальных дескрипторов для функций в klib88. */
 08437	  init_dataseg(&gdt[DS_286_INDEX], 0L, 0, TASK_PRIVILEGE);
 08438	  init_dataseg(&gdt[ES_286_INDEX], 0L, 0, TASK_PRIVILEGE);
 08439	
 08440	  /* Создание локальных дескрипторов в GDT для LDT таблицы процессов.
 08441	   * LDT выделяются при компиляции в таблице процессов и инициализируются при
 08442	   * инициализации или изменении карты процессов.
 08443	   */
 08444	  for (rp = BEG_PROC_ADDR, ldt_index = FIRST_LDT_INDEX;
 08445	       rp < END_PROC_ADDR; ++rp, ldt_index++) {
 08446	        init_dataseg(&gdt[ldt_index], vir2phys(rp->p_ldt),
 08447	                                     sizeof(rp->p_ldt), INTR_PRIVILEGE);
 08448	        gdt[ldt_index].access = PRESENT | LDT;
 08449	        rp->p_ldt_sel = ldt_index * DESC_SIZE;
 08450	  }
 08451	
 08452	  /* Создание основного сегмента TSS.
 08453	   * Он требуется только для хранения указателя стека, который используется после
 08454	   * прерывания.
 08455	   * Указатель устанавливается так, что прерывание автоматически сохраняет
 08456	   * текущие регистры процесса ip: cs: f: sp: ss в правильных элементах
 08457	   * таблицы процессов.
 08458	   */
 08459	  tss.ss0 = DS_SELECTOR;
 08460	  init_dataseg(&gdt[TSS_INDEX], vir2phys(&tss), sizeof(tss), INTR_PRIVILEGE);
 08461	  gdt[TSS_INDEX].access = PRESENT | (INTR_PRIVILEGE << DPL_SHIFT) | TSS_TYPE;
 08462	
 08463	  /* Создание дескрипторов для вентилей прерываний в IDT. */
 08464	  for (gtp = &gate_table[0];
 08465	       gtp < &gate_table[sizeof gate_table / sizeof gate_table[0]]; ++gtp) {
 08466	        int_gate(gtp->vec_nr, (vir_bytes) gtp->gate,
 08467	                 PRESENT | INT_GATE_TYPE | (gtp->privilege << DPL_SHIFT));
 08468	  }
 08469	
 08470	  /* Завершение создание основного сегмента TSS. */
 08471	  tss.iobase = sizeof tss;      /* пустая карта разрешений ввода-вывода */
 08472	}
	
 08474	/*===========================================================================*
 08475	 *                              init_codeseg                                 *
 08476	 *===========================================================================*/
 08477	PUBLIC void init_codeseg(segdp, base, size, privilege)
 08478	register struct segdesc_s *segdp;
 08479	phys_bytes base;
 08480	vir_bytes size;
 08481	int privilege;
 08482	{
 08483	/* Создание дескриптора сегмента кода. */
 08484	  sdesc(segdp, base, size);
 08485	  segdp->access = (privilege << DPL_SHIFT)
 08486	                | (PRESENT | SEGMENT | EXECUTABLE | READABLE);
 08487	                /* CONFORMING = 0, ACCESSED = 0 */
 08488	}
	
 08490	/*===========================================================================*
 08491	 *                              init_dataseg                                 *
 08492	 *===========================================================================*/
 08493	PUBLIC void init_dataseg(segdp, base, size, privilege)
 08494	register struct segdesc_s *segdp;
 08495	phys_bytes base;
 08496	vir_bytes size;
 08497	int privilege;
 08498	{
 08499	/* Создание дескриптора сегмента данных. */
 08500	  sdesc(segdp, base, size);
 08501	  segdp->access = (privilege << DPL_SHIFT) | (PRESENT | SEGMENT | WRITEABLE);
 08502	                /* EXECUTABLE = 0, EXPAND_DOWN = 0, ACCESSED = 0 */
 08503	}
	
 08505	/*===========================================================================*
 08506	 *                              sdesc                                        *
 08507	 *===========================================================================*/
 08508	PRIVATE void sdesc(segdp, base, size)
 08509	register struct segdesc_s *segdp;
 08510	phys_bytes base;
 08511	vir_bytes size;
 08512	{
 08513	/* Заполнение полей размеров (база, предел и гранулярность) дескриптора. */
 08514	  segdp->base_low = base;
 08515	  segdp->base_middle = base >> BASE_MIDDLE_SHIFT;
 08516	  segdp->base_high = base >> BASE_HIGH_SHIFT;
 08517	
 08518	  --size;                       /* преобразование в предел, нулевой размер означает 4G */
 08519	  if (size > BYTE_GRAN_MAX) {
 08520	        segdp->limit_low = size >> PAGE_GRAN_SHIFT;
 08521	        segdp->granularity = GRANULAR | (size >>
 08522	                                     (PAGE_GRAN_SHIFT + GRANULARITY_SHIFT));
 08523	  } else {
 08524	        segdp->limit_low = size;
 08525	        segdp->granularity = size >> GRANULARITY_SHIFT;
 08526	  }
 08527	  segdp->granularity |= DEFAULT;        /* означает BIG для сегмента данных */
 08528	}
	
 08530	/*===========================================================================*
 08531	 *                              seg2phys                                     *
 08532	 *===========================================================================*/
 08533	PUBLIC phys_bytes seg2phys(seg)
 08534	U16_t seg;
 08535	{
 08536	/* Возврат базового адреса сегмента, seg – либо сегментный регистр 8086, либо селектор
 08537	 * сегмента 286/386.
 08538	 */
 08539	  phys_bytes base;
 08540	  struct segdesc_s *segdp;
 08541	
 08542	  if (! machine.protected) {
 08543	        base = hclick_to_physb(seg);
 08544	  } else {
 08545	        segdp = &gdt[seg >> 3];
 08546	        base =    ((u32_t) segdp->base_low << 0)
 08547	                | ((u32_t) segdp->base_middle << 16)
 08548	                | ((u32_t) segdp->base_high << 24);
 08549	  }
 08550	  return base;
 08551	}
	
 08553	/*===========================================================================*
 08554	 *                              phys2seg                                     *
 08555	 *===========================================================================*/
 08556	PUBLIC void phys2seg(seg, off, phys)
 08557	u16_t *seg;
 08558	vir_bytes *off;
 08559	phys_bytes phys;
 08560	{
 08561	/* Возврат селектора сегмента и смещения, которые могут быть использованы для обращения к
 08562	 * физическому адресу драйвером, осуществляющим ввод-вывод в диапазоне адресов A0000 - DFFFF.
 08563	 */
 08564	  *seg = FLAT_DS_SELECTOR;
 08565	  *off = phys;
 08566	}
	
 08568	/*===========================================================================*
 08569	 *                              int_gate                                     *
 08570	 *===========================================================================*/
 08571	PRIVATE void int_gate(vec_nr, offset, dpl_type)
 08572	unsigned vec_nr;
 08573	vir_bytes offset;
 08574	unsigned dpl_type;
 08575	{
 08576	/* Создание дескриптора вентиля прерываний. */
 08577	  register struct gatedesc_s *idp;
 08578	
 08579	  idp = &idt[vec_nr];
 08580	  idp->offset_low = offset;
 08581	  idp->selector = CS_SELECTOR;
 08582	  idp->p_dpl_type = dpl_type;
 08583	  idp->offset_high = offset >> OFFSET_HIGH_SHIFT;
 08584	}
	
 08586	/*===========================================================================*
 08587	 *                              enable_iop                                   * 
 08588	 *===========================================================================*/
 08589	PUBLIC void enable_iop(pp)
 08590	struct proc *pp;
 08591	{
 08592	/* Позволяет пользовательскому процессу задействовать команды ввода-вывода. Измените биты
 08593	 * разрешений ввода-вывода в psw. Они определяют самый меньший уровень текущих привилегий,
 08594	 * при котором разрешено исполнение команд ввода-вывода. Пользователи и серверы имеют уровень 3. 
 08595	 * Уровень привилегий не может быть меньше. У ядра он равен 0, а у заданий – 1.
 08596	 */
 08597	  pp->p_reg.psw |= 0x3000;
 08598	}
	
 08600	/*===========================================================================*
 08601	 *                              alloc_segments                               *
 08602	 *===========================================================================*/
 08603	PUBLIC void alloc_segments(rp)
 08604	register struct proc *rp;
 08605	{
 08606	/* Вызывается при инициализации системы функцией main(), а также функцией do_newmap(). 
 08607	 * Этот код имеет отдельную функцию из-за особенностей конкретного аппаратного обеспечения.
 08608	 * Обратите внимание на то, что процесс IDLE входит в ядро и ему назначается привилегия TASK_PRIVILEGE.
 08609	 */
 08610	  phys_bytes code_bytes;
 08611	  phys_bytes data_bytes;
 08612	  int privilege;
 08613	
 08614	  if (machine.protected) {
 08615	      data_bytes = (phys_bytes) (rp->p_memmap[S].mem_vir + 
 08616	          rp->p_memmap[S].mem_len) << CLICK_SHIFT;
 08617	      if (rp->p_memmap[T].mem_len == 0)
 08618	          code_bytes = data_bytes;      /* совместные код и данные, плохая защита */
 08619	      else
 08620	          code_bytes = (phys_bytes) rp->p_memmap[T].mem_len << CLICK_SHIFT;
 08621	      privilege = (iskernelp(rp)) ? TASK_PRIVILEGE :  USER_PRIVILEGE;
 08622	      init_codeseg(&rp->p_ldt[CS_LDT_INDEX],
 08623	          (phys_bytes) rp->p_memmap[T].mem_phys << CLICK_SHIFT,
 08624	          code_bytes, privilege);
 08625	      init_dataseg(&rp->p_ldt[DS_LDT_INDEX],
 08626	          (phys_bytes) rp->p_memmap[D].mem_phys << CLICK_SHIFT,
 08627	          data_bytes, privilege);
 08628	      rp->p_reg.cs = (CS_LDT_INDEX * DESC_SIZE) | TI | privilege;
 08629	      rp->p_reg.gs =
 08630	      rp->p_reg.fs =
 08631	      rp->p_reg.ss =
 08632	      rp->p_reg.es =
 08633	      rp->p_reg.ds = (DS_LDT_INDEX*DESC_SIZE) | TI | privilege;
 08634	  } else {
 08635	      rp->p_reg.cs = click_to_hclick(rp->p_memmap[T].mem_phys);
 08636	      rp->p_reg.ss =
 08637	      rp->p_reg.es =
 08638	      rp->p_reg.ds = click_to_hclick(rp->p_memmap[D].mem_phys);
 08639	  }
 08640	}
	




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/klib.s
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 08700	#
 08701	! Выбор между версиями низкоуровневого кода ядра для процессоров 8086 и 386.
 08702	
 08703	#include <minix/config.h>
 08704	#if _WORD_SIZE == 2
 08705	#include "klib88.s"
 08706	#else
 08707	#include "klib386.s"
 08708	#endif


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/klib386.s
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 08800	# 
 08801	! разделы
 08802	
 08803	.sect .text; .sect .rom; .sect .data; .sect .bss
 08804	
 08805	#include <minix/config.h>
 08806	#include <minix/const.h>
 08807	#include "const.h"
 08808	#include "sconst.h"
 08809	#include "protect.h"
 08810	
 08811	! Этот файл содержит множество ассемблерных подпрограмм, используемых ядром.
 08812	! Они перечислены далее: 
 08813	
 08814	.define _monitor        ! выход из Minix и возврат в монитор
 08815	.define _int86          ! разрешение монитору выполнить вызов прерывания 8086
 08816	.define _cp_mess        ! копирование сообщений источника в приемник
 08817	.define _exit           ! заполнитель для библиотечных процедур
 08818	.define __exit          ! заполнитель для библиотечных процедур
 08819	.define ___exit         ! заполнитель для библиотечных процедур
 08820	.define ___main         ! заполнитель для GCC
 08821	.define _phys_insw      ! передача данных из порта дискового контроллера в память
 08822	.define _phys_insb      ! то же, но побайтно
 08823	.define _phys_outsw     ! передача данных из памяти в порт дискового контроллера
 08824	.define _phys_outsb     ! то же, но побайтно
 08825	.define _enable_irq     ! разрешение прерывания контроллера 8259
 08826	.define _disable_irq    ! запрещение прерывания
 08827	.define _phys_copy      ! копирование данных между двумя областями памяти
 08828	.define _phys_memset    ! запись эталона в память
 08829	.define _mem_rdw        ! копирование слова из адреса [сегмент: смещение]
 08830	.define _reset          ! перезапуск системы
 08831	.define _idle_task      ! запуск задания IDLE при простое системы
 08832	.define _level0         ! вызов функции на уровне 0
 08833	.define _read_tsc       ! чтение счетчика цикла (процессоры Pentium и выше)
 08834	.define _read_cpu_flags ! чтение флагов процессора
 08835	
 08836	! Процедуры гарантируют сохранение только тех регистров, сохранение которых предполагает
 08837	! C-компилятор (ebx, esi, edi, ebp, esp, сегментные регистры и бит направления во флагах).
 08838	!
 08839	
 08840	.sect .text
 08841	!*===========================================================================*
 08842	!*                              monitor                                      *
 08843	!*===========================================================================*
 08844	! PUBLIC void monitor();
 08845	! Возврат в монитор.
 08846	
 08847	_monitor: 
 08848	        mov     esp, (_mon_sp)          ! восстановление указателя стека монитора
 08849	    o16 mov     dx, SS_SELECTOR         ! сегмент данных монитора
 08850	        mov     ds, dx
 08851	        mov     es, dx
 08852	        mov     fs, dx
 08853	        mov     gs, dx
 08854	        mov     ss, dx
 08855	        pop     edi
 08856	        pop     esi
 08857	        pop     ebp
 08858	    o16 retf                            ! возврат в монитор
 08859	
 08860	
 08861	!*===========================================================================*
 08862	!*                              int86                                        *
 08863	!*===========================================================================*
 08864	! PUBLIC void int86();
 08865	_int86: 
 08866	        cmpb    (_mon_return), 0        ! is the monitor there?
 08867	        jnz     0f
 08868	        movb    ah, 0x01                ! ошибка int 13 кажется подходящей
 08869	        movb    (_reg86+ 0), ah         ! reg86.w.f = 1 (установка флага заема)
 08870	        movb    (_reg86+13), ah         ! reg86.b.ah = 0x01 = "недопустимая команда"
 08871	        ret
 08872	0:       push    ebp                    ! сохранение C-регистров
 08873	        push    esi
 08874	        push    edi
 08875	        push    ebx
 08876	        pushf                           ! сохранение флагов
 08877	        cli                             ! очистка прерываний
 08878	
 08879	        inb     INT2_CTLMASK
 08880	        movb    ah, al
 08881	        inb     INT_CTLMASK
 08882	        push    eax                     ! сохранение масок прерываний
 08883	        mov     eax, (_irq_use)         ! назначение используемых прерываний
 08884	        and     eax, ~[1<<CLOCK_IRQ]    ! продолжение отсчета часов
 08885	        outb    INT_CTLMASK             ! разрешение всех неиспользуемых прерываний
 08886	        movb    al, ah
 08887	        outb    INT2_CTLMASK
 08888	
 08889	        mov     eax, SS_SELECTOR        ! наблюдение сегмента данных
 08890	        mov     ss, ax
 08891	        xchg    esp, (_mon_sp)          ! переключение стеков
 08892	        push    (_reg86+36)             ! параметры, используемые в вызове INT
 08893	        push    (_reg86+32)
 08894	        push    (_reg86+28)
 08895	        push    (_reg86+24)
 08896	        push    (_reg86+20)
 08897	        push    (_reg86+16)
 08898	        push    (_reg86+12)
 08899	        push    (_reg86+ 8)
 08900	        push    (_reg86+ 4)
 08901	        push    (_reg86+ 0)
 08902	        mov     ds, ax                  ! оставшиеся селекторы данных
 08903	        mov     es, ax
 08904	        mov     fs, ax
 08905	        mov     gs, ax
 08906	        push    cs
 08907	        push    return                  ! адрес возврата в ядро и селектор ядра
 08908	    o16 jmpf    20+2*4+10*4+2*4(esp)    ! выполнение вызова
 08909	return: 
 08910	        pop     (_reg86+ 0)
 08911	        pop     (_reg86+ 4)
 08912	        pop     (_reg86+ 8)
 08913	        pop     (_reg86+12)
 08914	        pop     (_reg86+16)
 08915	        pop     (_reg86+20)
 08916	        pop     (_reg86+24)
 08917	        pop     (_reg86+28)
 08918	        pop     (_reg86+32)
 08919	        pop     (_reg86+36)
 08920	        lgdt    (_gdt+GDT_SELECTOR)     ! перезагрузка глобальной таблицы дескрипторов
 08921	        jmpf    CS_SELECTOR: csinit     ! восстановление всего
 08922	csinit:  mov     eax, DS_SELECTOR
 08923	        mov     ds, ax
 08924	        mov     es, ax
 08925	        mov     fs, ax
 08926	        mov     gs, ax
 08927	        mov     ss, ax
 08928	        xchg    esp, (_mon_sp)          ! обратное переключение стеков
 08929	        lidt    (_gdt+IDT_SELECTOR)     ! перезагрузка таблицы дескрипторов прерываний
 08930	        andb    (_gdt+TSS_SELECTOR+DESC_ACCESS), ~0x02  ! очистка бита занятости TSS
 08931	        mov     eax, TSS_SELECTOR
 08932	        ltr     ax                      ! установка регистра TSS
 08933	
 08934	        pop     eax
 08935	        outb    INT_CTLMASK             ! восстановление масок прерываний
 08936	        movb    al, ah
 08937	        outb    INT2_CTLMASK
 08938	
 08939	        add     (_lost_ticks), ecx      ! учет числа пропущенных тактов
 08940	
 08941	        popf                            ! восстановление флагов
 08942	        pop     ebx                     ! восстановление С-регистров
 08943	        pop     edi
 08944	        pop     esi
 08945	        pop     ebp
 08946	        ret
 08947	
 08948	
 08949	!*===========================================================================*
 08950	!*                              cp_mess                                      *
 08951	!*===========================================================================*
 08952	! PUBLIC void cp_mess(int src, phys_clicks src_clicks, vir_bytes src_offset,
 08953	!                     phys_clicks dst_clicks, vir_bytes dst_offset);
 08954	! Эта подпрограмма быстро копирует сообщение из любого местоположения в адресном пространстве
 08955	! в любое другое местоположение. Она также копирует адрес источника сообщения, указанный
 08956	! в параметре вызова, в первое слово сообщения. 
 08957	!
 08958	! Обратите внимание на то, что размер сообщения "Msize" задает в двойных словах (DWORD), а
 08959	! не в байтах. Изменение определения сообщения в файле типов без соответствующих изменений
 08960	! здесь приведет к полному краху системы.
 08961	
 08962	CM_ARGS =       4 + 4 + 4 + 4 + 4       ! 4 + 4 + 4 + 4 + 4
 08963	!               es  ds edi esi eip      proc scl sof dcl dof
 08964	
 08965	        .align  16
 08966	_cp_mess: 
 08967	        cld
 08968	        push    esi
 08969	        push    edi
 08970	        push    ds
 08971	        push    es
 08972	
 08973	        mov     eax, FLAT_DS_SELECTOR
 08974	        mov     ds, ax
 08975	        mov     es, ax
 08976	
 08977	        mov     esi, CM_ARGS+4(esp)             ! кликов источника
 08978	        shl     esi, CLICK_SHIFT
 08979	        add     esi, CM_ARGS+4+4(esp)           ! смещение источника
 08980	        mov     edi, CM_ARGS+4+4+4(esp)         ! кликов приемника
 08981	        shl     edi, CLICK_SHIFT
 08982	        add     edi, CM_ARGS+4+4+4+4(esp)       ! смещение приемника
 08983	
 08984	        mov     eax, CM_ARGS(esp)       ! номер процесса источника
 08985	        stos                            ! копирование номера источника в сообщение
 08986	        add     esi, 4                  ! не копировать первое слово
 08987	        mov     ecx, Msize - 1          ! запомнить, первое слово не считается 
 08988	        rep
 08989	        movs                            ! копирование сообщения
 08990	
 08991	        pop     es
 08992	        pop     ds
 08993	        pop     edi
 08994	        pop     esi
 08995	        ret                             ! конец!
 08996	
 08997	
 08998	!*===========================================================================*
 08999	!*                              exit                                         *
 09000	!*===========================================================================*
 09001	! PUBLIC void exit();
 09002	! Некоторые библиотечные функции вызывают exit, поэтому должна быть пустая версия.
 09003	! Фактические вызовы exit не могут происходить в ядре.
 09004	! GNU CC по неясным причинам "любит" вызывать ___main из main().
 09005	
 09006	_exit: 
 09007	__exit: 
 09008	___exit: 
 09009	        sti
 09010	        jmp     ___exit
 09011	
 09012	___main: 
 09013	        ret
 09014	
 09015	
 09016	!*===========================================================================*
 09017	!*                              phys_insw                                    *
 09018	!*===========================================================================*
 09019	! PUBLIC void phys_insw(Port_t port, phys_bytes buf, size_t count);
 09020	! Чтение массива из порта ввода-вывода. Версия insw() с абсолютным адресом.
 09021	
 09022	_phys_insw: 
 09023	        push    ebp
 09024	        mov     ebp, esp
 09025	        cld
 09026	        push    edi
 09027	        push    es
 09028	        mov     ecx, FLAT_DS_SELECTOR
 09029	        mov     es, cx
 09030	        mov     edx, 8(ebp)             ! порт для чтения
 09031	        mov     edi, 12(ebp)            ! адрес приемника
 09032	        mov     ecx, 16(ebp)            ! счетчик байтов
 09033	        shr     ecx, 1                  ! счетчик слов
 09034	rep o16 ins                             ! ввод множества слов
 09035	        pop     es
 09036	        pop     edi
 09037	        pop     ebp
 09038	        ret
 09039	
 09040	
 09041	!*===========================================================================*
 09042	!*                              phys_insb                                    *
 09043	!*===========================================================================*
 09044	! PUBLIC void phys_insb(Port_t port, phys_bytes buf, size_t count);
 09045	! Ввод массива из порта ввода-вывода. Версия insb() с абсолютным адресом.
 09046	
 09047	_phys_insb: 
 09048	        push    ebp
 09049	        mov     ebp, esp
 09050	        cld
 09051	        push    edi
 09052	        push    es
 09053	        mov     ecx, FLAT_DS_SELECTOR
 09054	        mov     es, cx
 09055	        mov     edx, 8(ebp)             ! порт для чтения
 09056	        mov     edi, 12(ebp)            ! адрес приемника
 09057	        mov     ecx, 16(ebp)            ! счетчик байтов
 09058	!       shr     ecx, 1                  ! счетчик слов
 09059	   rep  insb                            ! ввод множества слов
 09060	        pop     es
 09061	        pop     edi
 09062	        pop     ebp
 09063	        ret
 09064	
 09065	
 09066	!*===========================================================================*
 09067	!*                              phys_outsw                                   *
 09068	!*===========================================================================*
 09069	! PUBLIC void phys_outsw(Port_t port, phys_bytes buf, size_t count);
 09070	! Вывод массива в порт ввода-вывода. Версия outsw() с абсолютным адресом.
 09071	
 09072	        .align  16
 09073	_phys_outsw: 
 09074	        push    ebp
 09075	        mov     ebp, esp
 09076	        cld
 09077	        push    esi
 09078	        push    ds
 09079	        mov     ecx, FLAT_DS_SELECTOR
 09080	        mov     ds, cx
 09081	        mov     edx, 8(ebp)             ! порт для записи
 09082	        mov     esi, 12(ebp)            ! адрес источника
 09083	        mov     ecx, 16(ebp)            ! счетчик байтов
 09084	        shr     ecx, 1                  ! счетчик слов
 09085	rep o16 outs                            ! вывод множества слов
 09086	        pop     ds
 09087	        pop     esi
 09088	        pop     ebp
 09089	        ret
 09090	
 09091	
 09092	!*===========================================================================*
 09093	!*                              phys_outsb                                   *
 09094	!*===========================================================================*
 09095	! PUBLIC void phys_outsb(Port_t port, phys_bytes buf, size_t count);
 09096	! Вывод массива в порт ввода-вывода. Версия outsb() с абсолютным адресом.
 09097	
 09098	        .align  16
 09099	_phys_outsb: 
 09100	        push    ebp
 09101	        mov     ebp, esp
 09102	        cld
 09103	        push    esi
 09104	        push    ds
 09105	        mov     ecx, FLAT_DS_SELECTOR
 09106	        mov     ds, cx
 09107	        mov     edx, 8(ebp)             ! порт для записи
 09108	        mov     esi, 12(ebp)            ! адрес источника
 09109	        mov     ecx, 16(ebp)            ! счетчик байтов
 09110	   rep  outsb                           ! вывод множества байтов
 09111	        pop     ds
 09112	        pop     esi
 09113	        pop     ebp
 09114	        ret
 09115	
 09116	
 09117	!*==========================================================================*
 09118	!*                              enable_irq                                  *
 09119	!*==========================================================================*/
 09120	! PUBLIC void enable_irq(irq_hook_t *hook)
 09121	! Разрешение запроса линии прерывания путем очистки бита 8259.
 09122	! Эквивалентный C-код для hook->irq < 8: 
 09123	!   if ((irq_actids[hook->irq] &= ~hook->id) == 0)
 09124	!       outb(INT_CTLMASK, inb(INT_CTLMASK) & ~(1 << irq));
 09125	
 09126	        .align  16
 09127	_enable_irq: 
 09128	        push    ebp
 09129	        mov     ebp, esp
 09130	        pushf
 09131	        cli
 09132	        mov     eax, 8(ebp)             ! обработчик
 09133	        mov     ecx, 8(eax)             ! irq
 09134	        mov     eax, 12(eax)            ! бит id
 09135	        not     eax
 09136	        and     _irq_actids(ecx*4), eax ! очистка этого id-бита
 09137	        jnz     en_done                 ! маскировано ли прерывание другими обработчиками?
 09138	        movb    ah, ~1
 09139	        rolb    ah, cl                  ! ah = ~(1 << (irq % 8))
 09140	        mov     edx, INT_CTLMASK        ! разрешить irq < 8 на главном контроллере 8259
 09141	        cmpb    cl, 8
 09142	        jb      0f
 09143	        mov     edx, INT2_CTLMASK       ! разрешить irq >= 8 на подчиненном контроллере 8259
 09144	0:       inb     dx
 09145	        andb    al, ah
 09146	        outb    dx                      ! очистить бит контроллера 8259
 09147	en_done: popf
 09148	        leave
 09149	        ret
 09150	
 09151	
 09152	!*==========================================================================*
 09153	!*                              disable_irq                                 *
 09154	!*==========================================================================*/
 09155	! PUBLIC int disable_irq(irq_hook_t *hook)
 09156	! Запретить запрос линии прерывания путем установки бита контроллера 8259.
 09157	! Эквивалентный C-код для irq < 8: 
 09158	!   irq_actids[hook->irq] |= hook->id;
 09159	!   outb(INT_CTLMASK, inb(INT_CTLMASK) | (1 << irq));
 09160	! Возвращает true, если прерывание не было запрещено ранее.
 09161	
 09162	        .align  16
 09163	_disable_irq: 
 09164	        push    ebp
 09165	        mov     ebp, esp
 09166	        pushf
 09167	        cli
 09168	        mov     eax, 8(ebp)             ! обработчик
 09169	        mov     ecx, 8(eax)             ! irq
 09170	        mov     eax, 12(eax)            ! бит id
 09171	        or      _irq_actids(ecx*4), eax ! установка этого бита
 09172	        movb    ah, 1
 09173	        rolb    ah, cl                  ! ah = (1 << (irq % 8))
 09174	        mov     edx, INT_CTLMASK        ! запрещение irq < 8 на главном контроллере 8259
 09175	        cmpb    cl, 8
 09176	        jb      0f
 09177	        mov     edx, INT2_CTLMASK       ! запрещение irq >= 8 на подчиненном контроллере 8259
 09178	0:       inb     dx
 09179	        testb   al, ah
 09180	        jnz     dis_already             ! было ли прерывание запрещено ранее?
 09181	        orb     al, ah
 09182	        outb    dx                      ! установка бита контроллера 8259
 09183	        mov     eax, 1                  ! запрещаемого данной функцией
 09184	        popf
 09185	        leave
 09186	        ret
 09187	dis_already: 
 09188	        xor     eax, eax                ! прерывание уже запрещено
 09189	        popf
 09190	        leave
 09191	        ret
 09192	
 09193	
 09194	!*===========================================================================*
 09195	!*                              phys_copy                                    *
 09196	!*===========================================================================*
 09197	! PUBLIC void phys_copy(phys_bytes source, phys_bytes destination,
 09198	!                       phys_bytes bytecount);
 09199	! Копирование блока физической памяти.
 09200	
 09201	PC_ARGS =       4 + 4 + 4 + 4   ! 4 + 4 + 4
 09202	!               es edi esi eip   src dst len
 09203	
 09204	        .align  16
 09205	_phys_copy: 
 09206	        cld
 09207	        push    esi
 09208	        push    edi
 09209	        push    es
 09210	
 09211	        mov     eax, FLAT_DS_SELECTOR
 09212	        mov     es, ax
 09213	
 09214	        mov     esi, PC_ARGS(esp)
 09215	        mov     edi, PC_ARGS+4(esp)
 09216	        mov     eax, PC_ARGS+4+4(esp)
 09217	
 09218	        cmp     eax, 10                 ! избежание выравнивания для небольших фрагментов
 09219	        jb      pc_small
 09220	        mov     ecx, esi                ! выравнивание источника
 09221	        neg     ecx
 09222	        and     ecx, 3                  ! число для выравнивания
 09223	        sub     eax, ecx
 09224	        rep
 09225	   eseg movsb
 09226	        mov     ecx, eax
 09227	        shr     ecx, 2                  ! число двойных слов
 09228	        rep
 09229	   eseg movs
 09230	        and     eax, 3
 09231	pc_small: 
 09232	        xchg    ecx, eax                ! остаток
 09233	        rep
 09234	   eseg movsb
 09235	
 09236	        pop     es
 09237	        pop     edi
 09238	        pop     esi
 09239	        ret
 09240	
 09241	!*===========================================================================*
 09242	!*                              phys_memset                                  *
 09243	!*===========================================================================*
 09244	! PUBLIC void phys_memset(phys_bytes source, unsigned long pattern,
 09245	!       phys_bytes bytecount);
 09246	! Заполнение блока физической памяти заданным значением.
 09247	
 09248	        .align  16
 09249	_phys_memset: 
 09250	        push    ebp
 09251	        mov     ebp, esp
 09252	        push    esi
 09253	        push    ebx
 09254	        push    ds
 09255	        mov     esi, 8(ebp)
 09256	        mov     eax, 16(ebp)
 09257	        mov     ebx, FLAT_DS_SELECTOR
 09258	        mov     ds, bx
 09259	        mov     ebx, 12(ebp)
 09260	        shr     eax, 2
 09261	fill_start: 
 09262	        mov     (esi), ebx
 09263	        add     esi, 4
 09264	        dec     eax
 09265	        jnz     fill_start
 09266	        ! остались ли байты?
 09267	        mov     eax, 16(ebp)
 09268	        and     eax, 3
 09269	remain_fill: 
 09270	        cmp     eax, 0
 09271	        jz      fill_done
 09272	        movb    bl, 12(ebp)
 09273	        movb    (esi), bl
 09274	        add     esi, 1
 09275	        inc     ebp
 09276	        dec     eax
 09277	        jmp     remain_fill
 09278	fill_done: 
 09279	        pop     ds
 09280	        pop     ebx
 09281	        pop     esi
 09282	        pop     ebp
 09283	        ret
 09284	
 09285	!*===========================================================================*
 09286	!*                              mem_rdw                                      *
 09287	!*===========================================================================*
 09288	! PUBLIC u16_t mem_rdw(U16_t segment, u16_t *offset);
 09289	! Загрузка и возврат слова по дальнему указателю segment: offset.
 09290	
 09291	        .align  16
 09292	_mem_rdw: 
 09293	        mov     cx, ds
 09294	        mov     ds, 4(esp)              ! сегмент
 09295	        mov     eax, 4+4(esp)           ! смещение
 09296	        movzx   eax, (eax)              ! возвращаемое слово
 09297	        mov     ds, cx
 09298	        ret
 09299	
 09300	
 09301	!*===========================================================================*
 09302	!*                              reset                                        *
 09303	!*===========================================================================*
 09304	! PUBLIC void reset();
 09305	! Перезагрузка системы за счет загрузки таблицы IDT со смещением 0 и прерывания.
 09306	
 09307	_reset: 
 09308	        lidt    (idt_zero)
 09309	        int     3               ! может быть все, что угодно, процессору 386 это не понравится
 09310	.sect .data
 09311	idt_zero:        .data4  0, 0
 09312	.sect .text
 09313	
 09314	
 09315	!*===========================================================================*
 09316	!*                              idle_task                                    *
 09317	!*===========================================================================*
 09318	_idle_task: 
 09319	! Это задание вызывается, когда у системы нет полезной работы. Команда HLT переводит
 09320	! процессор в состояние, в котором он потребляет минимум энергии.
 09321	        push    halt
 09322	        call    _level0         ! level0(halt)
 09323	        pop     eax
 09324	        jmp     _idle_task
 09325	halt: 
 09326	        sti
 09327	        hlt
 09328	        cli
 09329	        ret
 09330	
 09331	!*===========================================================================*
 09332	!*                            level0                                         *
 09333	!*===========================================================================*
 09334	! PUBLIC void level0(void (*func)(void))
 09335	! Вызов функции с уровнем разрешения 0. Это позволяет заданиям ядра выполнять действия,
 09336	! разрешенные на самом привилегированном уровне процессора.
 09337	!
 09338	_level0: 
 09339	        mov     eax, 4(esp)
 09340	        mov     (_level0_func), eax
 09341	        int     LEVEL0_VECTOR
 09342	        ret
 09343	
 09344	
 09345	!*===========================================================================*
 09346	!*                            read_tsc                                       *
 09347	!*===========================================================================*
 09348	! PUBLIC void read_tsc(unsigned long *high, unsigned long *low);
 09349	! Чтение счетчика циклов процессора (Pentium и выше). 
 09350	.align 16
 09351	_read_tsc: 
 09352	.data1 0x0f             ! команда RDTSC
 09353	.data1 0x31             ! помещает TSC в EDX: EAX
 09354	        push ebp
 09355	        mov ebp, 8(esp)
 09356	        mov (ebp), edx
 09357	        mov ebp, 12(esp)
 09358	        mov (ebp), eax
 09359	        pop ebp
 09360	        ret
 09361	
 09362	!*===========================================================================*
 09363	!*                            read_flags                                             *
 09364	!*===========================================================================*
 09365	! PUBLIC unsigned long read_cpu_flags(void);
 09366	! Чтение флагов состояния процессора из C.
 09367	.align 16
 09368	_read_cpu_flags: 
 09369	        pushf
 09370	        mov eax, (esp)
 09371	        popf
 09372	        ret
 09373	
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/utility.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 09400	/* Этот файл содержит набор разнообразных процедур: 
 09401	 *   panic -          прекращение работы MINIX в случае неисправимой ошибки
 09402	 *   kprintf -        вывод диагностической информации о ядре
 09403	 *
 09404	 * Изменения: 
 09405	 *   10 декабря 2004 —  печать ядра с использованием циклического буфера (Jorrit N. Herder)
 09406	 * 
 09407	 * Этот файл содержит подпрограммы, работающие с сообщениями ядра, а именно с выводом
 09408	 * диагностической информации внутри ядра. Сообщения ядра не отображаются непосредственно
 09409	 * на консоли, поскольку эту задачу должен решать драйвер вывода. Вместо этого ядро
 09410	 * накапливает символы в буфере и посылает драйверу вывода уведомление, когда новое
 09411	 * сообщение готово. 
 09412	 */
 09413	
 09414	#include <minix/com.h>
 09415	#include "kernel.h"
 09416	#include <stdarg.h>
 09417	#include <unistd.h>
 09418	#include <stddef.h>
 09419	#include <stdlib.h>
 09420	#include <signal.h>
 09421	#include "proc.h"
 09422	
 09423	#define END_OF_KMESS    -1
 09424	FORWARD _PROTOTYPE(void kputc, (int c));
 09425	
 09426	/*===========================================================================*
 09427	 *                              panic                                        *
 09428	 *===========================================================================*/
 09429	PUBLIC void panic(mess,nr)
 09430	_CONST char *mess;
 09431	int nr;
 09432	{
 09433	/* В ядре системы произошла неисправимая ошибка. Прекращение выполнения. */
 09434	  static int panicking = 0;
 09435	  if (panicking ++) return;             /* предотвращение рекурсивных сбоев */
 09436	
 09437	  if (mess != NULL) {
 09438	        kprintf("\nKernel panic:  %s", mess);
 09439	        if (nr != NO_NUM) kprintf(" %d", nr);
 09440	        kprintf("\n",NO_NUM);
 09441	  }
 09442	
 09443	  /* Выход из MINIX. */
 09444	  prepare_shutdown(RBT_PANIC);
 09445	}
	
 09447	/*===========================================================================*
 09448	 *                              kprintf                                      *
 09449	 *===========================================================================*/
 09450	PUBLIC void kprintf(const char *fmt, ...)       /* формат печати */
 09451	{
 09452	  int c;                                        /* следующий символ в fmt */
 09453	  int d;
 09454	  unsigned long u;                              /* численный аргумент */
 09455	  int base;                                     /* база численного аргумента */
 09456	  int negative = 0;                             /* печать знака - */
 09457	  static char x2c[] = "0123456789ABCDEF";       /* таблица преобразования чисел */
 09458	  char ascii[8 * sizeof(long) / 3 + 2];         /* строка для ascii-числа */
 09459	  char *s = NULL;                               /* строка для печати */
 09460	  va_list argp;                                 /* дополнительные аргументы */
 09461	  
 09462	  va_start(argp, fmt);                          /* аргументы инициализации переменной */
 09463	
 09464	  while((c=*fmt++) != 0) {
 09465	
 09466	      if (c == '%') {                           /* формат '%ключ' */
 09467	          switch(c = *fmt++) {                  /* определение действия */
 09468	
 09469	          /* Известные ключи: %d, %u, %x, %s и %%. Этот набор можно легко расширить
 09470	           * типами %b и %o, указав другую базу.
 09471	           * Ключи числовых типов не устанавливают строку в 's', а используют общее
 09472	           * преобразование после оператора switch.
 09473	           */ 
 09474	          case 'd':                              /* вывод десятичного числа */
 09475	              d = va_arg(argp, signed int);
 09476	              if (d < 0) { negative = 1; u = -d; }  else { u = d; }
 09477	              base = 10;
 09478	              break;
 09479	          case 'u':                              /* вывод безззнакового числа типа long */
 09480	              u = va_arg(argp, unsigned long);
 09481	              base = 10;
 09482	              break;
 09483	          case 'x':                              /* вывод шестнадцатеричного числа */
 09484	              u = va_arg(argp, unsigned long);
 09485	              base = 0x10;
 09486	              break;
 09487	          case 's':                              /* вывод строки */
 09488	              s = va_arg(argp, char *);
 09489	              if (s == NULL) s = "(null)";
 09490	              break;
 09491	          case '%':                              /* вывод процента */
 09492	              s = "%";                           
 09493	              break;                    
 09494	
 09495	          /* нераспознанный ключ. */
 09496	          default:                               /* вывод %ключ */
 09497	              s = "%?";                         
 09498	              s[1] = c;                         /* установка неизвестного ключа */
 09499	          }
 09500	
 09501	          /* Если не задана строка, считаем числом. Преобразование в ascii. */
 09502	          if (s == NULL) {
 09503	              s = ascii + sizeof(ascii)-1;
 09504	              *s = 0;                   
 09505	              do {  *--s = x2c[(u % base)]; }   /* назад */
 09506	              while ((u /= base) > 0); 
 09507	          }
 09508	
 09509	          /* Фактический вывод для формата "%ключ". */
 09510	          if (negative) kputc('-');             /* печать знака, если число отрицательное */
 09511	          while(*s != 0) { kputc(*s++); }       /* печать строки/числа */
 09512	          s = NULL;                             /* сброс для следующей итерации */
 09513	      }
 09514	      else {
 09515	          kputc(c);                             /* печать и продолжение */
 09516	      }
 09517	  }
 09518	  kputc(END_OF_KMESS);                          /* завершение вывода */
 09519	  va_end(argp);                                 /* конец переменных аргументов */
 09520	}
	
 09522	/*===========================================================================*
 09523	 *                              kputc                                        *
 09524	 *===========================================================================*/
 09525	PRIVATE void kputc(c)
 09526	int c;                                  /* символ для добавления */
 09527	{
 09528	/* Добавление символа для сообщения ядра. При появлении END_OF_KMESS передача уведомления
 09529	 * драйверу вывода. 
 09530	 */
 09531	  if (c != END_OF_KMESS) {
 09532	      kmess.km_buf[kmess.km_next] = c;  /* помещение обычного символа в буфер */
 09533	      if (kmess.km_size < KMESS_BUF_SIZE)
 09534	          kmess.km_size += 1;           
 09535	      kmess.km_next = (kmess.km_next + 1) % KMESS_BUF_SIZE;
 09536	  } else {
 09537	      send_sig(OUTPUT_PROC_NR, SIGKMESS);
 09538	  }
 09539	}
	





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/system.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 09600	/* Прототипы функций для системной библиотеки.  
 09601	 * Реализация содержится в файле src/kernel/system/.  
 09602	 *
 09603	 * Системная библиотека обеспечивает доступ к системным службам путем вызовов ядра.
 09604	 * Вызовы ядра преобразуются в сообщения-запросы к заданию SYS, ответственному за их 
 09605	 * обработку. По соглашению sys_call() преобразуется в сообщение с типом SYS_CALL, которое
 09606	 * обрабатывается функцией do_call().
 09607	 */ 
 09608	
 09609	#ifndef SYSTEM_H
 09610	#define SYSTEM_H
 09611	
 09612	/* Заголовочные файлы системной библиотеки. */
 09613	#include "kernel.h"
 09614	#include "proto.h"
 09615	#include "proc.h"
 09616	
 09617	/* Обработчик по умолчанию для неиспользуемых вызовов ядра. */
 09618	_PROTOTYPE( int do_unused, (message *m_ptr) );
 09619	_PROTOTYPE( int do_exec, (message *m_ptr) );            
 09620	_PROTOTYPE( int do_fork, (message *m_ptr) );
 09621	_PROTOTYPE( int do_newmap, (message *m_ptr) );
 09622	_PROTOTYPE( int do_exit, (message *m_ptr) );
 09623	_PROTOTYPE( int do_trace, (message *m_ptr) );   
 09624	_PROTOTYPE( int do_nice, (message *m_ptr) );
 09625	_PROTOTYPE( int do_copy, (message *m_ptr) );    
 09626	#define do_vircopy      do_copy
 09627	#define do_physcopy     do_copy
 09628	_PROTOTYPE( int do_vcopy, (message *m_ptr) );           
 09629	#define do_virvcopy     do_vcopy
 09630	#define do_physvcopy    do_vcopy
 09631	_PROTOTYPE( int do_umap, (message *m_ptr) );
 09632	_PROTOTYPE( int do_memset, (message *m_ptr) );
 09633	_PROTOTYPE( int do_abort, (message *m_ptr) );
 09634	_PROTOTYPE( int do_getinfo, (message *m_ptr) );
 09635	_PROTOTYPE( int do_privctl, (message *m_ptr) ); 
 09636	_PROTOTYPE( int do_segctl, (message *m_ptr) );
 09637	_PROTOTYPE( int do_irqctl, (message *m_ptr) );
 09638	_PROTOTYPE( int do_devio, (message *m_ptr) );
 09639	_PROTOTYPE( int do_vdevio, (message *m_ptr) );
 09640	_PROTOTYPE( int do_int86, (message *m_ptr) );
 09641	_PROTOTYPE( int do_sdevio, (message *m_ptr) );
 09642	_PROTOTYPE( int do_kill, (message *m_ptr) );
 09643	_PROTOTYPE( int do_getksig, (message *m_ptr) );
 09644	_PROTOTYPE( int do_endksig, (message *m_ptr) );
 09645	_PROTOTYPE( int do_sigsend, (message *m_ptr) );
 09646	_PROTOTYPE( int do_sigreturn, (message *m_ptr) );
 09647	_PROTOTYPE( int do_times, (message *m_ptr) );           
 09648	_PROTOTYPE( int do_setalarm, (message *m_ptr) );        
 09649	
 09650	#endif  /* SYSTEM_H */
 09651	
 09652	
 09653	


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/system.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 09700	/* Это задание обеспечивает интерфейс между ядром и системными процессами, находящимися в
 09701	 * пространстве пользователя. Доступ к системным службам осуществляется за счет вызовов
 09702	 * ядра. Вызовы ядра преобразуются в сообщения-запросы, обрабатываемые этим заданием.
 09703	 * По соглашению sys_call() преобразуется в сообщение с типом SYS_CALL, которое
 09704	 * обрабатывается функцией do_call(). 
 09705	 *
 09706	 * Для сопоставления вызовов ядра обрабатывающим их функциям используется закрытый
 09707	 * вектор вызовов. Фактические функции-обработчики помещены в отдельные файлы для того,
 09708	 * чтобы не перегружать этот файл содержимым. Вектор вызовов используется в главном цикле
 09709	 * системного задания для обработки всех входящих вызовов.
 09710	 *
 09711	 * В дополнение к основной точке входа sys_task(), запускающей главный цикл, имеется
 09712	 * ряд других точек входа: 
 09713	 *   get_priv:       назначение структуры привилегий пользователю или системному процессу
 09714	 *   send_sig:       передача сигнала непосредственно системному процессу
 09715	 *   cause_sig:      выполнение действия, вызывающего появление сигнала через менеджер процессов
 09716	 *   umap_local:     сопоставление виртуального адреса в LOCAL_SEG физическому адресу 
 09717	 *   umap_remote:    сопоставление виртуального адреса в REMOTE_SEG физическому адресу
 09718	 *   umap_bios:      сопоставление виртуального адреса в BIOS_SEG физическому адресу
 09719	 *   virtual_copy:   копирование байтов из одного виртуального адреса в другой
 09720	 *   get_randomness: накопление случайных чисел в буфере
 09721	 *
 09722	 * Изменения: 
 09723	 *   04 августа 2005:  проверка, разрешен ли вызов ядра (Jorrit N. Herder)
 09724	 *   20 июля 2005:     передача сигнала службам с помощью сообщения (Jorrit N. Herder) 
 09725	 *   15 января 2005:   новая, обобщенная функция виртуального копирования (Jorrit N. Herder)
 09726	 *   10 октября 2004:  обработка системных вызовов, упакованных в вектор вызовов (Jorrit N. Herder)
 09727	 *   30 сентября 2004: обновление документации исходного кода (Jorrit N. Herder)
 09728	 */
 09729	
 09730	#include "kernel.h"
 09731	#include "system.h"
 09732	#include <stdlib.h>
 09733	#include <signal.h>
 09734	#include <unistd.h>
 09735	#include <sys/sigcontext.h>
 09736	#include <ibm/memory.h>
 09737	#include "protect.h"
 09738	
 09739	/* Объявление вектора вызовов, определяющего соответствие между вызовами ядра и функциями-
 09740	 * обработчиками. Инициализация вектора происходит в функции sys_init() с помощью функции 
 09741	 * map(), которая гарантирует корректность номеров вызовов ядра. Память не выделяется,
 09742	 * поскольку заполнитель объявлен как внешний. При совершении недопустимого вызова размер 
 09743	 * массива будет отрицательным, что приведет к ошибке во время компиляции. 
 09744	 */
 09745	PUBLIC int (*call_vec[NR_SYS_CALLS])(message *m_ptr);
 09746	
 09747	#define map(call_nr, handler) \
 09748	    {extern int dummy[NR_SYS_CALLS>(unsigned)(call_nr-KERNEL_CALL) ? 1: -1];} \
 09749	    call_vec[(call_nr-KERNEL_CALL)] = (handler)  
 09750	
 09751	FORWARD _PROTOTYPE( void initialize, (void));
 09752	
 09753	/*===========================================================================*
 09754	 *                              sys_task                                     *
 09755	 *===========================================================================*/
 09756	PUBLIC void sys_task()
 09757	{
 09758	/* Главная точка входа в sys_task. Получение сообщение и его обработка согласно типу. */
 09759	  static message m;
 09760	  register int result;
 09761	  register struct proc *caller_ptr;
 09762	  unsigned int call_nr;
 09763	  int s;
 09764	
 09765	  /* Инициализация системного задания. */
 09766	  initialize();
 09767	
 09768	  while (TRUE) {
 09769	      /* Получение работы. Блокирование и ожидание появления сообщения-запроса. */
 09770	      receive(ANY, &m);                 
 09771	      call_nr = (unsigned) m.m_type - KERNEL_CALL;      
 09772	      caller_ptr = proc_addr(m.m_source);       
 09773	
 09774	      /* Проверка допустимости запроса и попытка его обработки. */
 09775	      if (! (priv(caller_ptr)->s_call_mask & (1<<call_nr))) {
 09776	          kprintf("SYSTEM:  request %d from %d denied.\n", call_nr,m.m_source);
 09777	          result = ECALLDENIED;                 /* недопустимый тип сообщения */
 09778	      } else if (call_nr >= NR_SYS_CALLS) {     /* проверка номера вызова */
 09779	          kprintf("SYSTEM:  illegal request %d from %d.\n", call_nr,m.m_source);
 09780	          result = EBADREQUEST;                 /* недопустимый тип сообщения */
 09781	      } 
 09782	      else {
 09783	          result = (*call_vec[call_nr])(&m);    /* обработка вызова ядра */
 09784	      }
 09785	
 09786	      /* Передача ответа, если это не запрещено функцией-обработчиком. Использование функции
 09787	       * lock_send() для предотвращения перехвата системного вызова. Приемник гарантированно
 09788	       * блокирован в ожидании ответа.
 09789	       */
 09790	      if (result != EDONTREPLY) {
 09791	          m.m_type = result;                    /* ответ о состоянии вызова */
 09792	          if (OK != (s=lock_send(m.m_source, &m))) {
 09793	              kprintf("SYSTEM, reply to %d failed:  %d\n", m.m_source, s);
 09794	          }
 09795	      }
 09796	  }
 09797	}
	
 09799	/*===========================================================================*
 09800	 *                              initialize                                   *
 09801	 *===========================================================================*/
 09802	PRIVATE void initialize(void)
 09803	{
 09804	  register struct priv *sp;
 09805	  int i;
 09806	
 09807	  /* Инициализация обработчиков прерываний. Все обработчики помечены доступными */
 09808	  for (i=0; i<NR_IRQ_HOOKS; i++) {
 09809	      irq_hooks[i].proc_nr = NONE;
 09810	  }
 09811	
 09812	  /* Инициализация всех сторожевых таймеров всех процессов. */
 09813	  for (sp=BEG_PRIV_ADDR; sp < END_PRIV_ADDR; sp++) {
 09814	    tmr_inittimer(&(sp->s_alarm_timer));
 09815	  }
 09816	
 09817	  /* Инициализация вектора вызовов безопасным обработчиком по умолчанию. Некоторые вызовы 
 09818	   * ядра могут быть отключены или не существовать. В этом случае известным вызовам явно 
 09819	   * назначаются функции-обработчики. Это делается с помощью макроса, приводящего к ошибке
 09820	   * компиляции, если номер вызова некорректен. Очередность инициализации не имеет значения.
 09821	   */
 09822	  for (i=0; i<NR_SYS_CALLS; i++) {
 09823	      call_vec[i] = do_unused;
 09824	  }
 09825	
 09826	  /* управление процессами. */
 09827	  map(SYS_FORK, do_fork);               /* процесс породил новый процесс */
 09828	  map(SYS_EXEC, do_exec);               /* обновить процесс после исполнения */
 09829	  map(SYS_EXIT, do_exit);               /* очистка после завершения процесса */
 09830	  map(SYS_NICE, do_nice);               /* установка приоритета планирования */
 09831	  map(SYS_PRIVCTL, do_privctl);         /* управление системными привилегиями */
 09832	  map(SYS_TRACE, do_trace);             /* запрос трассировки */
 09833	
 09834	  /* Обработка сигналов. */
 09835	  map(SYS_KILL, do_kill);               /* передача сигнала процессу */
 09836	  map(SYS_GETKSIG, do_getksig);         /* менеджер процессов проверяет активные сигналы */
 09837	  map(SYS_ENDKSIG, do_endksig);         /* менеджер процессов завершил обработку сигнала */
 09838	  map(SYS_SIGSEND, do_sigsend);         /* запуск сигнала в стиле POSIX */
 09839	  map(SYS_SIGRETURN, do_sigreturn);     /* возврат из сигнала в стиле POSIX */
 09840	
 09841	  /* ввод (вывод) с (на) устройства. */
 09842	  map(SYS_IRQCTL, do_irqctl);           /* действия по управлению прерываниями */ 
 09843	  map(SYS_DEVIO, do_devio);             /* inb, inw, inl, outb, outw, outl */ 
 09844	  map(SYS_SDEVIO, do_sdevio);           /* phys_insb, _insw, _outsb, _outsw */
 09845	  map(SYS_VDEVIO, do_vdevio);           /* вектор запросов ввода-вывода */ 
 09846	  map(SYS_INT86, do_int86);             /* вызовы BIOS в реальном режиме */ 
 09847	
 09848	  /* Управление памятью. */
 09849	  map(SYS_NEWMAP, do_newmap);           /* задание карты памяти процесса */
 09850	  map(SYS_SEGCTL, do_segctl);           /* добавление сегмента и получение селектора */
 09851	  map(SYS_MEMSET, do_memset);           /* запись символа в область памяти */
 09852	
 09853	  /* Копирование. */
 09854	  map(SYS_UMAP, do_umap);               /* сопоставление физического адреса виртуальному */
 09855	  map(SYS_VIRCOPY, do_vircopy);         /* использование полностью виртуальной адресации */
 09856	  map(SYS_PHYSCOPY, do_physcopy);       /* использование физической адресации */
 09857	  map(SYS_VIRVCOPY, do_virvcopy);       /* вектор запросов копирования */
 09858	  map(SYS_PHYSVCOPY, do_physvcopy);     /* вектор запросов копирования */
 09859	
 09860	  /* Функции таймера. */
 09861	  map(SYS_TIMES, do_times);             /* получение времени работы системы и процессов */
 09862	  map(SYS_SETALARM, do_setalarm);       /* планирование синхронного сигнала */
 09863	
 09864	  /* Управление системой. */
 09865	  map(SYS_ABORT, do_abort);             /* выход из MINIX */
 09866	  map(SYS_GETINFO, do_getinfo);         /* запрос системной информации */ 
 09867	}
	
 09869	/*===========================================================================*
 09870	 *                              get_priv                                     *
 09871	 *===========================================================================*/
 09872	PUBLIC int get_priv(rc, proc_type)
 09873	register struct proc *rc;               /* указатель на новый (дочерний) процесс */
 09874	int proc_type;                          /* флаг типа процесса (системный/пользовательский) */
 09875	{
 09876	/* Получение структуры привилегий. Все пользовательские процессы используют одну и ту же
 09877	 * структуру привилегий, а системные процессы – собственные структуры. 
 09878	 */
 09879	  register struct priv *sp;                     /* структура привилегий */
 09880	
 09881	  if (proc_type == SYS_PROC) {                  /* поиск новой записи */
 09882	      for (sp = BEG_PRIV_ADDR; sp < END_PRIV_ADDR; ++sp) 
 09883	          if (sp->s_proc_nr == NONE && sp->s_id != USER_PRIV_ID) break; 
 09884	      if (sp->s_proc_nr != NONE) return(ENOSPC);
 09885	      rc->p_priv = sp;                          /* назначение новой записи */
 09886	      rc->p_priv->s_proc_nr = proc_nr(rc);      /* ассоциирование */
 09887	      rc->p_priv->s_flags = SYS_PROC;           /* пометить как привилегированные */
 09888	  } else {
 09889	      rc->p_priv = &priv[USER_PRIV_ID];         /* использование общей записи */
 09890	      rc->p_priv->s_proc_nr = INIT_PROC_NR;     /* ассоциирование */
 09891	      rc->p_priv->s_flags = 0;                  /* начальных флагов нет */
 09892	  }
 09893	  return(OK);
 09894	}
	
 09896	/*===========================================================================*
 09897	 *                              get_randomness                               *
 09898	 *===========================================================================*/
 09899	PUBLIC void get_randomness(source)
 09900	int source;
 09901	{
 09902	/* На компьютерах с RDTSC (командой чтения счетчика цикла – процессоры pentium
 09903	 * и выше) эта функция применяется для сбора энтропии высокого разрешения. В противном
 09904	 * случае используйте таймер реального времени (тактовое разрешение).
 09905	 *
 09906	 * К сожалению, эта проверка совершается на этапе выполнения: мы не хотим компилировать
 09907	 * разные ядра для разных процессоров.
 09908	 *
 09909	 * На компьютерах без RDTSC используется функция read_clock().
 09910	 */
 09911	  int r_next;
 09912	  unsigned long tsc_high, tsc_low;
 09913	
 09914	  source %= RANDOM_SOURCES;
 09915	  r_next= krandom.bin[source].r_next;
 09916	  if (machine.processor > 486) {
 09917	      read_tsc(&tsc_high, &tsc_low);
 09918	      krandom.bin[source].r_buf[r_next] = tsc_low;
 09919	  } else {
 09920	      krandom.bin[source].r_buf[r_next] = read_clock();
 09921	  }
 09922	  if (krandom.bin[source].r_size < RANDOM_ELEMENTS) {
 09923	        krandom.bin[source].r_size ++;
 09924	  }
 09925	  krandom.bin[source].r_next = (r_next + 1 ) % RANDOM_ELEMENTS;
 09926	}
	
 09928	/*===========================================================================*
 09929	 *                              send_sig                                     *
 09930	 *===========================================================================*/
 09931	PUBLIC void send_sig(proc_nr, sig_nr)
 09932	int proc_nr;                    /* системный процесс, которому посылается сигнал */
 09933	int sig_nr;                     /* посылаемый сигнал, от 1 до _NSIG */
 09934	{
 09935	/* Уведомление системного процесса о сигнале. Это делается просто: передаваемый сигнал
 09936	 * заносится в карту активных сигналов, а затем процессу доставляется уведомление с 
 09937	 * отправителем SYSTEM.
 09938	 */ 
 09939	  register struct proc *rp;
 09940	
 09941	  rp = proc_addr(proc_nr);
 09942	  sigaddset(&priv(rp)->s_sig_pending, sig_nr);
 09943	  lock_notify(SYSTEM, proc_nr); 
 09944	}
	
 09946	/*===========================================================================*
 09947	 *                              cause_sig                                    *
 09948	 *===========================================================================*/
 09949	PUBLIC void cause_sig(proc_nr, sig_nr)
 09950	int proc_nr;                    /* приемник сигнала */
 09951	int sig_nr;                     /* посылаемый сигнал, от 1 до _NSIG */
 09952	{
 09953	/* Системный процесс хочет послать сигнал процессу. Примеры: 
 09954	 *  - HARDWARE хочет послать SIGSEGV после исключения процессора
 09955	 *  - TTY хочет послать SIGINT после получения DEL
 09956	 *  - FS хочет послать SIGPIPE при разрыве канала
 09957	 * Сигналы обрабатываются путем передачи сообщения менеджеру процессов. Эта функция
 09958	 * обрабатывает сигналы и гарантирует, что менеджер процессов получает их (для этого она 
 09959	 * отправляет уведомление). Процесс, которому посылается сигнал, блокируется, пока менеджер 
 09960	 * процессов не завершил обработку всех посланных сигналов. 
 09961	 * Состязания между вызовами этой функции и системными вызовами, обрабатывающими активные 
 09962	 * сигналы ядра, невозможны. Функции, связанные с сигналами, вызываются только тогда, когда 
 09963	 * пользовательский процесс приводит к исключению процессора и только на уровне ядра, 
 09964	 * выполняющемся до завершения.
 09965	 */
 09966	  register struct proc *rp;
 09967	
 09968	  /* Проверка, является ли уже сигнал активным. В противном случае обработка сигнала. */
 09969	  rp = proc_addr(proc_nr);
 09970	  if (! sigismember(&rp->p_pending, sig_nr)) {
 09971	      sigaddset(&rp->p_pending, sig_nr);
 09972	      if (! (rp->p_rts_flags & SIGNALED)) {             /* другой активный */
 09973	          if (rp->p_rts_flags == 0) lock_dequeue(rp);   /* исключение из очереди */
 09974	          rp->p_rts_flags |= SIGNALED | SIG_PENDING;    /* обновление флагов */
 09975	          send_sig(PM_PROC_NR, SIGKSIG);
 09976	      }
 09977	  }
 09978	}
	
 09980	/*===========================================================================*
 09981	 *                              umap_local                                   *
 09982	 *===========================================================================*/
 09983	PUBLIC phys_bytes umap_local(rp, seg, vir_addr, bytes)
 09984	register struct proc *rp;       /* указатель на запись таблицы процедур процесса */
 09985	int seg;                        /* T, D, or S segment */
 09986	vir_bytes vir_addr;             /* виртуальный адрес в байтах внутри сегмента */
 09987	vir_bytes bytes;                /* число копируемых байтов */
 09988	{
 09989	/* Вычисление физического адреса для заданного виртуального адреса. */
 09990	  vir_clicks vc;                /* виртуальный адрес в кликах */
 09991	  phys_bytes pa;                /* промежуточная переменная типа phys_bytes */
 09992	  phys_bytes seg_base;
 09993	
 09994	  /* Если 'seg' = D, то, возможно, 'seg' = S, и наоборот. С T двусмысленность исключена.
 09995	   * Если виртуальный адрес попадает в дыру, это вызывает проблему. На процессоре 8088
 09996	   * такое обращение к стеку, вероятно, является корректным, поскольку стековые ошибки не
 09997	   * обнаруживаются аппаратно. На процессоре 8088 дыра обозначается S и принимается, однако
 09998	   * на других машинах называется D и отвергается.
 09999	   * В этом отношении Atari ST и 8088 идентичны.
 10000	   */
 10001	
 10002	  if (bytes <= 0) return( (phys_bytes) 0);
 10003	  if (vir_addr + bytes <= vir_addr) return 0;   /* переполнение */
 10004	  vc = (vir_addr + bytes - 1) >> CLICK_SHIFT;   /* последний клик данных */
 10005	
 10006	  if (seg != T)
 10007	        seg = (vc < rp->p_memmap[D].mem_vir + rp->p_memmap[D].mem_len ? D :  S);
 10008	
 10009	  if ((vir_addr>>CLICK_SHIFT) >= rp->p_memmap[seg].mem_vir + 
 10010	        rp->p_memmap[seg].mem_len) return( (phys_bytes) 0 );
 10011	
 10012	  if (vc >= rp->p_memmap[seg].mem_vir + 
 10013	        rp->p_memmap[seg].mem_len) return( (phys_bytes) 0 );
 10014	
 10015	  seg_base = (phys_bytes) rp->p_memmap[seg].mem_phys;
 10016	  seg_base = seg_base << CLICK_SHIFT;   /* начало сегмента в байтах */
 10017	  pa = (phys_bytes) vir_addr;
 10018	  pa -= rp->p_memmap[seg].mem_vir << CLICK_SHIFT;
 10019	  return(seg_base + pa);
 10020	}
	
 10022	/*===========================================================================*
 10023	 *                              umap_remote                                  *
 10024	 *===========================================================================*/
 10025	PUBLIC phys_bytes umap_remote(rp, seg, vir_addr, bytes)
 10026	register struct proc *rp;       /* указатель на запись таблицы процедур процесса */
 10027	int seg;                        /* индекс удаленного сегмента */
 10028	vir_bytes vir_addr;             /* виртуальный адрес в байтах внутри сегмента */
 10029	vir_bytes bytes;                /* число байтов для копирования */
 10030	{
 10031	/* Вычисление физического адреса для заданного виртуального адреса. */
 10032	  struct far_mem *fm;
 10033	
 10034	  if (bytes <= 0) return( (phys_bytes) 0);
 10035	  if (seg < 0 || seg >= NR_REMOTE_SEGS) return( (phys_bytes) 0);
 10036	
 10037	  fm = &rp->p_priv->s_farmem[seg];
 10038	  if (! fm->in_use) return( (phys_bytes) 0);
 10039	  if (vir_addr + bytes > fm->mem_len) return( (phys_bytes) 0);
 10040	
 10041	  return(fm->mem_phys + (phys_bytes) vir_addr); 
 10042	}
	
 10044	/*===========================================================================*
 10045	 *                              umap_bios                                    *
 10046	 *===========================================================================*/
 10047	PUBLIC phys_bytes umap_bios(rp, vir_addr, bytes)
 10048	register struct proc *rp;       /* указатель на запись таблицы процедур процесса */
 10049	vir_bytes vir_addr;             /* виртуальный адрес в сегменте BIOS */
 10050	vir_bytes bytes;                /* число байтов для копирования */
 10051	{
 10052	/* Вычисление физического адреса памяти в BIOS. Примечание: в настоящее время нулевой адрес
 10053	 * BIOS (первый вектор прерываний BIOS) не считается ошибкой, однако, поскольку в этом случае
 10054	 * физический адрес также будет равен нулю, вызывающая функция воспримет это как ошибку.
 10055	 * Проблемой эта ситуация не является, так как никто не использует первый вектор прерываний
 10056	 * BIOS.  
 10057	 */
 10058	
 10059	  /* Проверка всех допустимых диапазонов. */
 10060	  if (vir_addr >= BIOS_MEM_BEGIN && vir_addr + bytes <= BIOS_MEM_END)
 10061	        return (phys_bytes) vir_addr;
 10062	  else if (vir_addr >= BASE_MEM_TOP && vir_addr + bytes <= UPPER_MEM_END)
 10063	        return (phys_bytes) vir_addr;
 10064	  kprintf("Warning, error in umap_bios, virtual address 0x%x\n", vir_addr);
 10065	  return 0;
 10066	}
	
 10068	/*===========================================================================*
 10069	 *                              virtual_copy                                 *
 10070	 *===========================================================================*/
 10071	PUBLIC int virtual_copy(src_addr, dst_addr, bytes)
 10072	struct vir_addr *src_addr;      /* виртуальный адрес источника */
 10073	struct vir_addr *dst_addr;      /* виртуальный адрес приемника */
 10074	vir_bytes bytes;                /* число байтов для копирования  */
 10075	{
 10076	/* Копирование байтов из виртуального адреса src_addr в виртуальный адрес dst_addr. 
 10077	 * Виртуальные адтеса могут быть в ABS, LOCAL_SEG, REMOTE_SEG и BIOS_SEG.
 10078	 */
 10079	  struct vir_addr *vir_addr[2]; /* виртуальные адреса источника и приемника */
 10080	  phys_bytes phys_addr[2];      /* абсолютные адреса источника и приемника */ 
 10081	  int seg_index;
 10082	  int i;
 10083	
 10084	  /* проверка количества копируемых байтов. */
 10085	  if (bytes <= 0) return(EDOM);
 10086	
 10087	  /* дополнительные проверки и сопоставление физических адресов виртуальным. */
 10088	  vir_addr[_SRC_] = src_addr;
 10089	  vir_addr[_DST_] = dst_addr;
 10090	  for (i=_SRC_; i<=_DST_; i++) {
 10091	
 10092	      /* Получение физического адреса. */
 10093	      switch((vir_addr[i]->segment & SEGMENT_TYPE)) {
 10094	      case LOCAL_SEG: 
 10095	          seg_index = vir_addr[i]->segment & SEGMENT_INDEX;
 10096	          phys_addr[i] = umap_local( proc_addr(vir_addr[i]->proc_nr), 
 10097	              seg_index, vir_addr[i]->offset, bytes );
 10098	          break;
 10099	      case REMOTE_SEG: 
 10100	          seg_index = vir_addr[i]->segment & SEGMENT_INDEX;
 10101	          phys_addr[i] = umap_remote( proc_addr(vir_addr[i]->proc_nr), 
 10102	              seg_index, vir_addr[i]->offset, bytes );
 10103	          break;
 10104	      case BIOS_SEG: 
 10105	          phys_addr[i] = umap_bios( proc_addr(vir_addr[i]->proc_nr),
 10106	              vir_addr[i]->offset, bytes );
 10107	          break;
 10108	      case PHYS_SEG: 
 10109	          phys_addr[i] = vir_addr[i]->offset;
 10110	          break;
 10111	      default: 
 10112	          return(EINVAL);
 10113	      }
 10114	
 10115	      /* Проверка успешности сопоставления. */
 10116	      if (phys_addr[i] <= 0 && vir_addr[i]->segment != PHYS_SEG) 
 10117	          return(EFAULT);
 10118	  }
 10119	
 10120	  /* Копирование байтов между физическими адресами. */
 10121	  phys_copy(phys_addr[_SRC_], phys_addr[_DST_], (phys_bytes) bytes);
 10122	  return(OK);
 10123	}
	



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/system/do_setalarm.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 10200	/* В данном файле реализован вызов ядра: 
 10201	 *   m_type:     SYS_SETALARM 
 10202	 *
 10203	 * Параметры вызова: 
 10204	 *    m2_l1:     ALRM_EXP_TIME           (время истечения)
 10205	 *    m2_i2:     ALRM_ABS_TIME           (является ли время истечения абсолютным)
 10206	 *    m2_l1:     ALRM_TIME_LEFT          (число оставшихся секунд)
 10207	 */
 10208	
 10209	#include "../system.h"
 10210	
 10211	#if USE_SETALARM
 10212	
 10213	FORWARD _PROTOTYPE( void cause_alarm, (timer_t *tp) );
 10214	
 10215	/*===========================================================================*
 10216	 *                              do_setalarm                                  *
 10217	 *===========================================================================*/
 10218	PUBLIC int do_setalarm(m_ptr)
 10219	message *m_ptr;                 /* указатель на сообщение-запрос */
 10220	{
 10221	/* Процесс запрашивает синхронный сигнал или хочет отменить запрос. */
 10222	  register struct proc *rp;     /* указатель на запрашивающий процесс */
 10223	  int proc_nr;                  /* процесс, ожидающий сигнал */
 10224	  long exp_time;                /* время истечения таймера */
 10225	  int use_abs_time;             /* использование абсолютного или относительного времени */
 10226	  timer_t *tp;                  /* структура таймера процесса */
 10227	  clock_t uptime;               /* для хранения текущего времени работы системы */
 10228	
 10229	  /* Извлечение параметров из сообщения-запроса. */
 10230	  exp_time = m_ptr->ALRM_EXP_TIME;      /* время истечения таймера */
 10231	  use_abs_time = m_ptr->ALRM_ABS_TIME;  /* флаг абсолютного времени */
 10232	  proc_nr = m_ptr->m_source;            /* процесс для прерывания позже */
 10233	  rp = proc_addr(proc_nr);
 10234	  if (! (priv(rp)->s_flags & SYS_PROC)) return(EPERM);
 10235	
 10236	  /* Получение структуры таймера и установка параметров для этого таймера. */
 10237	  tp = &(priv(rp)->s_alarm_timer);      
 10238	  tmr_arg(tp)->ta_int = proc_nr;        
 10239	  tp->tmr_func = cause_alarm; 
 10240	
 10241	  /* Возврат тактов, оставшихся от предыдущего сигнала. */
 10242	  uptime = get_uptime(); 
 10243	  if ((tp->tmr_exp_time != TMR_NEVER) && (uptime < tp->tmr_exp_time) ) {
 10244	      m_ptr->ALRM_TIME_LEFT = (tp->tmr_exp_time - uptime);
 10245	  } else {
 10246	      m_ptr->ALRM_TIME_LEFT = 0;
 10247	  }
 10248	
 10249	  /* Сброс/установка таймера в зависимости от времени истечения. */
 10250	  if (exp_time == 0) {
 10251	      reset_timer(tp);
 10252	  } else {
 10253	      tp->tmr_exp_time = (use_abs_time) ? exp_time :  exp_time + get_uptime();
 10254	      set_timer(tp, tp->tmr_exp_time, tp->tmr_func);
 10255	  }
 10256	  return(OK);
 10257	}
	
 10259	/*===========================================================================*
 10260	 *                              cause_alarm                                  *
 10261	 *===========================================================================*/
 10262	PRIVATE void cause_alarm(tp)
 10263	timer_t *tp;
 10264	{
 10265	/* Подпрограмма, вызываемая при срабатывании таймера процесса, запросившего синхронный
 10266	 * сигнал. Номер процесса хранится в аргументе таймера 'ta_int'. Процесс получает
 10267	 * уведомление от источника CLOCK.
 10268	 */
 10269	  int proc_nr = tmr_arg(tp)->ta_int;            /* получение номера процесса */
 10270	  lock_notify(CLOCK, proc_nr);                  /* уведомление процесса */
 10271	}
	
 10273	#endif /* USE_SETALARM */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/system/do_exec.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 10300	/* В данном файле реализован вызов ядра: 
 10301	 *   m_type:     SYS_EXEC
 10302	 *
 10303	 * Параметры вызова: 
 10304	 *    m1_i1:     PR_PROC_NR              (процесс, совершивший вызов exec)
 10305	 *    m1_p1:     PR_STACK_PTR            (новый указатель стека)
 10306	 *    m1_p2:     PR_NAME_PTR             (указатель на имя программы)
 10307	 *    m1_p3:     PR_IP_PTR               (новый счетчик команд)
 10308	 */
 10309	#include "../system.h"
 10310	#include <string.h>
 10311	#include <signal.h>
 10312	
 10313	#if USE_EXEC
 10314	
 10315	/*===========================================================================*
 10316	 *                              do_exec                                      *
 10317	 *===========================================================================*/
 10318	PUBLIC int do_exec(m_ptr)
 10319	register message *m_ptr;        /* указатель на сообщение-запрос */
 10320	{
 10321	/* Обработка sys_exec().  Процесс успешно выполнил EXEC, окончание. */
 10322	  register struct proc *rp;
 10323	  reg_t sp;                     /* новый sp */
 10324	  phys_bytes phys_name;
 10325	  char *np;
 10326	
 10327	  rp = proc_addr(m_ptr->PR_PROC_NR);
 10328	  sp = (reg_t) m_ptr->PR_STACK_PTR;
 10329	  rp->p_reg.sp = sp;            /* установка указателя стека */
 10330	  phys_memset(vir2phys(&rp->p_ldt[EXTRA_LDT_INDEX]), 0,
 10331	        (LDT_SIZE - EXTRA_LDT_INDEX) * sizeof(rp->p_ldt[0]));
 10332	  rp->p_reg.pc = (reg_t) m_ptr->PR_IP_PTR;      /* установка pc */
 10333	  rp->p_rts_flags &= ~RECEIVING;        /* менеджер процессов не отвечает на вызов EXEC */
 10334	  if (rp->p_rts_flags == 0) lock_enqueue(rp);
 10335	
 10336	  /* Сохранение имени команды для отладки, вывод ps(1) и т.д. */
 10337	  phys_name = numap_local(m_ptr->m_source, (vir_bytes) m_ptr->PR_NAME_PTR,
 10338	                                        (vir_bytes) P_NAME_LEN - 1);
 10339	  if (phys_name != 0) {
 10340	        phys_copy(phys_name, vir2phys(rp->p_name), (phys_bytes) P_NAME_LEN - 1);
 10341	        for (np = rp->p_name; (*np & BYTE) >= ' '; np++) {}
 10342	        *np = 0;                                        /* пометка конца */
 10343	  } else {
 10344	        strncpy(rp->p_name, "<unset>", P_NAME_LEN);
 10345	  }
 10346	  return(OK);
 10347	}
 10348	#endif /* USE_EXEC */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      kernel/clock.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 10400	/* Это файл таймерного задания, обрабатывающего функции, связанные со временем.
 10401	 * Важные события, обрабатываемые CLOCK – установка и наблюдение таймеров и определение
 10402	 * моментов планирования/перепланирования процессов. 
 10403	 * Задание CLOCK предоставляет прямой интерфейс с процессами ядра. Системные службы могут
 10404	 * получать доступ к своим службам через системные вызовы, например, sys_setalarm(). Задание
 10405	 * CLOCK, таким образом, скрыто от внешнего мира.  
 10406	 *
 10407	 * Изменения: 
 10408	 *   08 октября 2005:  изменен порядок кода и отредактированы комментарии (A. S. Woodhull)
 10409	 *   18 марта 2004:   интерфейс часов перемещен в задание SYSTEM (Jorrit N. Herder) 
 10410	 *   30 сентября 2004:   обновлена документация исходного кода (Jorrit N. Herder)
 10411	 *   24 сентября 2004:   переработаны таймеры синхронных сигналов (Jorrit N. Herder)
 10412	 *
 10413	 * Функция do_clocktick() вызывается обработчиком прерываний от таймера, когда сторожевой таймер 
 10414	 * истекает или требуется планирование процесса. 
 10415	 *
 10416	 * В дополнение к основной точке вход clock_task(), запускающей главный цикл, имеются 
 10417	 * несколько других точек входа: 
 10418	 *   clock_stop:         вызывается непосредственно перед завершением работы MINIX
 10419	 *   get_uptime:         получение реального времени с момента последней загрузки в тактах часов
 10420	 *   set_timer:          установка сторожевого таймера (+)
 10421	 *   reset_timer:        сброс сторожевого таймера (+)
 10422	 *   read_clock:         чтение счетчика канала 0 таймера 8253A
 10423	 *
 10424	 * (+) Задание CLOCK отслеживает сторожевые таймеры для всего ядра. Сторожевые функции
 10425	 * истекших таймеров исполняются в do_clocktick(). Важно, чтобы они не блокировались, иначе 
 10426	 * это может привести к блокированию задания CLOCK. Сообщение не следует отправлять
 10427	 * вызовом send(), когда приемник не ожидает его. Вместо этого следует использовать функцию
 10428	 * notify(), которая никогда не блокируется. 
 10429	 */
 10430	
 10431	#include "kernel.h"
 10432	#include "proc.h"
 10433	#include <signal.h>
 10434	#include <minix/com.h>
 10435	
 10436	/* Прототипы функций, объявляемых как PRIVATE */ 
 10437	FORWARD _PROTOTYPE( void init_clock, (void) );
 10438	FORWARD _PROTOTYPE( int clock_handler, (irq_hook_t *hook) );
 10439	FORWARD _PROTOTYPE( int do_clocktick, (message *m_ptr) );
 10440	
 10441	/* Параметры часов. */
 10442	#define COUNTER_FREQ (2*TIMER_FREQ) /* частота счетчика, использующего прямоугольные импульсы */
 10443	#define LATCH_COUNT     0x00    /* cc00xxxx, c = канал, x = любое */
 10444	#define SQUARE_WAVE     0x36    /* ccaammmb, a = доступ, m = режим, b = BCD */
 10445	                                /*   11x11, 11 = младший и старший биты, x11 = прямоуг. имп. */
 10446	#define TIMER_COUNT ((unsigned) (TIMER_FREQ/HZ)) /* начальное значение счетчика */
 10447	#define TIMER_FREQ  1193182L    /* частота таймера для PC и AT */
 10448	
 10449	#define CLOCK_ACK_BIT   0x80    /* бит подтверждения прерывания от таймера в PS/2 */
 10450	
 10451	/* Очередь таймеров задания CLOCK, которую обрабатывают функции файла <timers.h>. 
 10452	 * Каждый системный процесс имеет один синхронный таймер. Если другие части ядра
 10453	 * хотят использовать дополнительные таймеры, они должны объявить свои собственные 
 10454	 * постоянные (статические) структуры таймеров, которые могут передаваться часам через
 10455	 * функции (re)set_timer().
 10456	 * При истечении таймера его сторожевая функция запускается заданием CLOCK. 
 10457	 */
 10458	PRIVATE timer_t *clock_timers;          /* очередь таймеров CLOCK */
 10459	PRIVATE clock_t next_timeout;           /* реальное время истечения следующего таймера */
 10460	
 10461	/* Обработчик прерываний увеличивает время каждый такт часов. */
 10462	PRIVATE clock_t realtime;               /* часы реального времени */
 10463	PRIVATE irq_hook_t clock_hook;          /* обработчик прерываний */
 10464	
 10465	/*===========================================================================*
 10466	 *                              clock_task                                   *
 10467	 *===========================================================================*/
 10468	PUBLIC void clock_task()
 10469	{
 10470	/* Главная программа таймерного задания. Любой вызов, отличный от HARD_INT, считается ошибкой.
 10471	 */
 10472	  message m;                    /* буфер сообщения для ввода и вывода */
 10473	  int result;                   /* результат, возвращаемый обработчиком */
 10474	
 10475	  init_clock();                 /* инициализация таймерного задания */
 10476	
 10477	  /* Основной цикл таймерного задания. Получение и выполнение работы без отсылки ответов. */
 10478	  while (TRUE) {
 10479	
 10480	      /* Получение сообщения. */
 10481	      receive(ANY, &m); 
 10482	
 10483	      /* Обработка запроса. Ожидается только количество тактов часов. */
 10484	      switch (m.m_type) {
 10485	      case HARD_INT: 
 10486	          result = do_clocktick(&m);    /* обработка такта часов */
 10487	          break;
 10488	      default:                           /* недопустимый тип запроса */
 10489	          kprintf("CLOCK:  illegal request %d from %d.\n", m.m_type,m.m_source);
 10490	      }
 10491	  }
 10492	}
	
 10494	/*===========================================================================*
 10495	 *                              do_clocktick                                 *
 10496	 *===========================================================================*/
 10497	PRIVATE int do_clocktick(m_ptr)
 10498	message *m_ptr;                         /* указатель на сообщение-запрос */
 10499	{
 10500	/* Несмотря на название, эта процедура не вызывается каждый такт часов. Она вызывается
 10501	 * только в тех тактах, где выполняется много работы.
 10502	 */
 10503	
 10504	  /* Процесс израсходовал квант целиком. Обработчик прерываний сохранил этот процесс в
 10505	   * 'prev_ptr'. Сначала нужно гарантировать, что процесс не находится в какой-либо
 10506	   * из очередей планирования, а затем снова объявить его готовым. Поскольку у него больше 
 10507	   * нет времени, он получает новый квант и помещается в нужную позицию в очереди. Побочный 
 10508	   * эффект: новый процесс будет запланирован.
 10509	   */ 
 10510	  if (prev_ptr->p_ticks_left <= 0 && priv(prev_ptr)->s_flags & PREEMPTIBLE) {
 10511	      lock_dequeue(prev_ptr);           /* удаление из очередей */
 10512	      lock_enqueue(prev_ptr);           /* и постановка в очередь заново */ 
 10513	  }
 10514	
 10515	  /* Проверка, истек ли таймер, и запуск его сторожевой функции. */
 10516	  if (next_timeout <= realtime) { 
 10517	        tmrs_exptimers(&clock_timers, realtime, NULL);
 10518	        next_timeout = clock_timers == NULL ? 
 10519	                TMR_NEVER :  clock_timers->tmr_exp_time;
 10520	  }
 10521	
 10522	  /* Отмена передачи ответа. */
 10523	  return(EDONTREPLY);
 10524	}
	
 10526	/*===========================================================================*
 10527	 *                              init_clock                                   *
 10528	 *===========================================================================*/
 10529	PRIVATE void init_clock()
 10530	{
 10531	  /* Инициализация обработчика прерывания задания CLOCK. */
 10532	  clock_hook.proc_nr = CLOCK;
 10533	
 10534	  /* Инициализация канала 0 таймера 8253A, например, с частотой 60 Гц. */
 10535	  outb(TIMER_MODE, SQUARE_WAVE);        /* настройка таймера на постоянную работу */
 10536	  outb(TIMER0, TIMER_COUNT);            /* загрузка младшего байта таймера */
 10537	  outb(TIMER0, TIMER_COUNT >> 8);       /* загрузка старшего байта таймера  */
 10538	  put_irq_handler(&clock_hook, CLOCK_IRQ, clock_handler);/* регистрация обработчика */
 10539	  enable_irq(&clock_hook);              /* готовность к прерываниям от таймера */
 10540	}
	
 10542	/*===========================================================================*
 10543	 *                              clock_stop                                   *
 10544	 *===========================================================================*/
 10545	PUBLIC void clock_stop()
 10546	{
 10547	/* Сброс часов на частоту BIOS (для перезагрузки) */
 10548	  outb(TIMER_MODE, 0x36);
 10549	  outb(TIMER0, 0);
 10550	  outb(TIMER0, 0);
 10551	}
	
 10553	/*===========================================================================*
 10554	 *                              clock_handler                                *
 10555	 *===========================================================================*/
 10556	PRIVATE int clock_handler(hook)
 10557	irq_hook_t *hook;
 10558	{
 10559	/* Эта функция исполняется в каждом такте часов (то есть при каждом прерывании от
 10560	 * микросхемы часов). Она выполняет небольшие объемы работ, освобождая от необходимости  
 10561	 * вызывать таймерное задание каждый такт. Таймерное задание вызывается, когда: 
 10562	 *
 10563	 *      (1) квант времени текущего процесса закончился, либо когда
 10564	 *      (2) таймер истек и необходимо запустить сторожевую функцию.
 10565	 *
 10566	 * Здесь осуществляется доступ ко многим глобальным и статическим переменным. Безопасность 
 10567	 * этого доступа должна быть подтверждена. Весь код планирования и передачи сообщений 
 10568	 * временно запрещает прерывания, что исключает конфликты с вызовами уровня задания. Более 
 10569	 * того, повторный вход в прерывания невозможен, поэтому обработчик прерывания не может
 10570	 * быть вызван для обслуживания других прерываний.
 10571	 * 
 10572	 * Переменные, изменяемые обработчиком прерываний от таймера: 
 10573	 *      lost_ticks: 
 10574	 *              Число тактов часов вне таймерного задания. К примеру, оно используется, когда
 10575	 *              монитор загрузки обрабатывает прерывание в реальном режиме.
 10576	 *      realtime: 
 10577	 *              К текущему времени работы системы прибавляются все потерянные такты.
 10578	 *      proc_ptr, bill_ptr: 
 10579	 *              Используются для учета. При условии, что они всегда являются корректными
 10580	 *              указателями, неважно, изменяются ли они в файле proc.c, поскольку в худшем
 10581	 *              случае время будет начислено предыдущему процессу.
 10582	 */
 10583	  register unsigned ticks;
 10584	
 10585	  /* Подтверждение прерывания от таймера PS/2. */
 10586	  if (machine.ps_mca) outb(PORT_B, inb(PORT_B) | CLOCK_ACK_BIT);
 10587	
 10588	  /* Получение числа тактов и обновление реального времени. */
 10589	  ticks = lost_ticks + 1;
 10590	  lost_ticks = 0;
 10591	  realtime += ticks;
 10592	
 10593	  /* Обновление учетного времени пользователя и системы. Начисление времени пользователя
 10594	   * текущему процессу. Если начислить время текущему процессу нельзя (то есть он не
 10595	   * является пользовательским), процессу, которому можно начислить время, начисляется
 10596	   * также и системное время.
 10597	   */
 10598	  proc_ptr->p_user_time += ticks;
 10599	  if (priv(proc_ptr)->s_flags & PREEMPTIBLE) {
 10600	      proc_ptr->p_ticks_left -= ticks;
 10601	  }
 10602	  if (! (priv(proc_ptr)->s_flags & BILLABLE)) {
 10603	      bill_ptr->p_sys_time += ticks;
 10604	      bill_ptr->p_ticks_left -= ticks;
 10605	  }
 10606	
 10607	  /* Проверка необходимости вызова do_clocktick(). Выполняется для оповещений и
 10608	   * планирования. Некоторые процессы, например, задания ядра, не могут быть вытеснены. 
 10609	   */ 
 10610	  if ((next_timeout <= realtime) || (proc_ptr->p_ticks_left <= 0)) {
 10611	      prev_ptr = proc_ptr;                      /* сохранение выполняющегося процесса */
 10612	      lock_notify(HARDWARE, CLOCK);             /* посылка уведомления */
 10613	  } 
 10614	  return(1);                                    /* разрешение прерываний */
 10615	}
	
 10617	/*===========================================================================*
 10618	 *                              get_uptime                                   *
 10619	 *===========================================================================*/
 10620	PUBLIC clock_t get_uptime()
 10621	{
 10622	/* Получение и возврат текущего времени работы системы в тактах. */
 10623	  return(realtime);
 10624	}
	
 10626	/*===========================================================================*
 10627	 *                              set_timer                                    *
 10628	 *===========================================================================*/
 10629	PUBLIC void set_timer(tp, exp_time, watchdog)
 10630	struct timer *tp;               /* указатель на структуру таймера */
 10631	clock_t exp_time;               /* реальное время истечения таймера */
 10632	tmr_func_t watchdog;            /* сторожевая функция */
 10633	{
 10634	/* Помещение нового таймера в список активных таймеров. Следующее время истечения всегда 
 10635	 * обновляется и устанавливается 
 10636	 */
 10637	  tmrs_settimer(&clock_timers, tp, exp_time, watchdog, NULL);
 10638	  next_timeout = clock_timers->tmr_exp_time;
 10639	}
	
 10641	/*===========================================================================*
 10642	 *                              reset_timer                                  *
 10643	 *===========================================================================*/
 10644	PUBLIC void reset_timer(tp)
 10645	struct timer *tp;               /* указатель на структуру таймера */
 10646	{
 10647	/* Таймер, на который указывает указатель 'tp', больше не нужен. Он удаляется из списков
 10648	 * активных и истекших таймеров. Следующее время истечения всегда обновляется и 
 10649	 * устанавливается равным времени истечения первого таймера в списке.
 10650	 */
 10651	  tmrs_clrtimer(&clock_timers, tp, NULL);
 10652	  next_timeout = (clock_timers == NULL) ? 
 10653	        TMR_NEVER :  clock_timers->tmr_exp_time;
 10654	}
	
 10656	/*===========================================================================*
 10657	 *                              read_clock                                   *
 10658	 *===========================================================================*/
 10659	PUBLIC unsigned long read_clock()
 10660	{
 10661	/* Чтение счетчика канала 0 таймера 8253A. Этот счетчик уменьшается с частотой TIMER_FREQ
 10662	 * и сбрасывается в значение TIMER_COUNT-1 по достижении нуля. Когда значение счетчика
 10663	 * становится нулевым, происходит аппаратное прерывание (такт часов), которое и перезапускает
 10664	 * цикл счетчика.  
 10665	 */
 10666	  unsigned count;
 10667	
 10668	  outb(TIMER_MODE, LATCH_COUNT);
 10669	  count = inb(TIMER0);
 10670	  count |= (inb(TIMER0) << 8);
 10671	  
 10672	  return count;
 10673	}


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      drivers/drivers.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 10700	/* Главный заголовочный файл для всех драйверов устройств. Он включает в себя другие файлы
 10701	 * и определяет основные константы.
 10702	 */
 10703	#define _POSIX_SOURCE      1    /* заголовочные файлы должны включать содержимое для POSIX */
 10704	#define _MINIX             1    /* заголовочные файлы должны включать содержимое для MINIX */
 10705	#define _SYSTEM            1    /* получение отрицательного номера ошибки в <errno.h> */
 10706	
 10707	/* Основные заголовочные файлы, включаемые в файлы *.c автоматически. */
 10708	#include <minix/config.h>       /* ДОЛЖЕН быть первым */
 10709	#include <ansi.h>               /* ДОЛЖЕН быть вторым */
 10710	#include <minix/type.h>
 10711	#include <minix/com.h>
 10712	#include <minix/dmap.h>
 10713	#include <minix/callnr.h>
 10714	#include <sys/types.h>
 10715	#include <minix/const.h>
 10716	#include <minix/devio.h>
 10717	#include <minix/syslib.h>
 10718	#include <minix/sysutil.h>
 10719	#include <minix/bitmap.h>
 10720	
 10721	#include <ibm/interrupt.h>      /* векторы прерываний и различные порты */
 10722	#include <ibm/bios.h>           /* индексы BIOS */
 10723	#include <ibm/ports.h>          /* зарезервированные порты */
 10724	
 10725	#include <string.h>
 10726	#include <signal.h>
 10727	#include <stdlib.h>
 10728	#include <limits.h>
 10729	#include <stddef.h>
 10730	#include <errno.h>
 10731	#include <unistd.h>
 10732	



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      drivers/libdriver/driver.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 10800	/* Типы и константы, используемые общим и зависимым от устройств кодом драйверов
 10801	 * устройств.
 10802	 */
 10803	
 10804	#define _POSIX_SOURCE      1    /* заголовочные файлы должны включать содержимое для POSIX */
 10805	#define _MINIX             1    /* заголовочные файлы должны включать содержимое для MINIX */
 10806	#define _SYSTEM            1    /* получение отрицательного номера ошибки в <errno.h> */
 10807	
 10808	/* Основные заголовочные файлы, включаемые в файлы *.c автоматически. */
 10809	#include <minix/config.h>       /* ДОЛЖЕН быть первым */
 10810	#include <ansi.h>               /* ДОЛЖЕН быть вторым */
 10811	#include <minix/type.h>
 10812	#include <minix/ipc.h>
 10813	#include <minix/com.h>
 10814	#include <minix/callnr.h>
 10815	#include <sys/types.h>
 10816	#include <minix/const.h>
 10817	#include <minix/syslib.h>
 10818	#include <minix/sysutil.h>
 10819	
 10820	#include <string.h>
 10821	#include <limits.h>
 10822	#include <stddef.h>
 10823	#include <errno.h>
 10824	
 10825	#include <minix/partition.h>
 10826	#include <minix/u64.h>
 10827	
 10828	/* Информация о коде, независимом от устройств, и точки входа в него. */
 10829	struct driver {
 10830	  _PROTOTYPE( char *(*dr_name), (void) );
 10831	  _PROTOTYPE( int (*dr_open), (struct driver *dp, message *m_ptr) );
 10832	  _PROTOTYPE( int (*dr_close), (struct driver *dp, message *m_ptr) );
 10833	  _PROTOTYPE( int (*dr_ioctl), (struct driver *dp, message *m_ptr) );
 10834	  _PROTOTYPE( struct device *(*dr_prepare), (int device) );
 10835	  _PROTOTYPE( int (*dr_transfer), (int proc_nr, int opcode, off_t position,
 10836	                                        iovec_t *iov, unsigned nr_req) );
 10837	  _PROTOTYPE( void (*dr_cleanup), (void) );
 10838	  _PROTOTYPE( void (*dr_geometry), (struct partition *entry) );
 10839	  _PROTOTYPE( void (*dr_signal), (struct driver *dp, message *m_ptr) );
 10840	  _PROTOTYPE( void (*dr_alarm), (struct driver *dp, message *m_ptr) );
 10841	  _PROTOTYPE( int (*dr_cancel), (struct driver *dp, message *m_ptr) );
 10842	  _PROTOTYPE( int (*dr_select), (struct driver *dp, message *m_ptr) );
 10843	  _PROTOTYPE( int (*dr_other), (struct driver *dp, message *m_ptr) );
 10844	  _PROTOTYPE( int (*dr_hw_int), (struct driver *dp, message *m_ptr) );
 10845	};
 10846	
 10847	#if (CHIP == INTEL)
 10848	
 10849	/* Число байтов памяти, к которым можно обращаться напрямую (DMA) до границы 64K:  */
 10850	#define dma_bytes_left(phys)    \
 10851	   ((unsigned) (sizeof(int) == 2 ? 0 :  0x10000) - (unsigned) ((phys) & 0xFFFF))
 10852	
 10853	#endif /* CHIP == INTEL */
 10854	
 10855	/* Базовый адрес и размер раздела в байтах. */
 10856	struct device {
 10857	  u64_t dv_base;
 10858	  u64_t dv_size;
 10859	};
 10860	
 10861	#define NIL_DEV         ((struct device *) 0)
 10862	
 10863	/* Функции, определенные в driver.c:  */
 10864	_PROTOTYPE( void driver_task, (struct driver *dr) );
 10865	_PROTOTYPE( char *no_name, (void) );
 10866	_PROTOTYPE( int do_nop, (struct driver *dp, message *m_ptr) );
 10867	_PROTOTYPE( struct device *nop_prepare, (int device) );
 10868	_PROTOTYPE( void nop_cleanup, (void) );
 10869	_PROTOTYPE( void nop_task, (void) );
 10870	_PROTOTYPE( void nop_signal, (struct driver *dp, message *m_ptr) );
 10871	_PROTOTYPE( void nop_alarm, (struct driver *dp, message *m_ptr) );
 10872	_PROTOTYPE( int nop_cancel, (struct driver *dp, message *m_ptr) );
 10873	_PROTOTYPE( int nop_select, (struct driver *dp, message *m_ptr) );
 10874	_PROTOTYPE( int do_diocntl, (struct driver *dp, message *m_ptr) );
 10875	
 10876	/* Параметры диска. */
 10877	#define SECTOR_SIZE      512    /* размер физического сектора в байтах */
 10878	#define SECTOR_SHIFT       9    /* для деления */
 10879	#define SECTOR_MASK      511    /* и остатка */
 10880	
 10881	/* Размер буфера DMA в байтах. */
 10882	#define USE_EXTRA_DMA_BUF  0    /* обычно не требуется */
 10883	#define DMA_BUF_SIZE    (DMA_SECTORS * SECTOR_SIZE)
 10884	
 10885	#if (CHIP == INTEL)
 10886	extern u8_t *tmp_buf;                   /* буфер DMA */
 10887	#else
 10888	extern u8_t tmp_buf[];                  /* буфер DMA */
 10889	#endif
 10890	extern phys_bytes tmp_phys;             /* физический адрес буфера DMA */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      drivers/libdriver/drvlib.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 10900	/* определения драйверов устройств IBM                     Автор:  Kees J. Bot
 10901	 *                                                              7 декабря 1995
 10902	 */
 10903	
 10904	#include <ibm/partition.h>
 10905	
 10906	_PROTOTYPE( void partition, (struct driver *dr, int device, int style, int atapi) );
 10907	
 10908	/* структура таблицы параметров BIOS. */
 10909	#define bp_cylinders(t)         (* (u16_t *) (&(t)[0]))
 10910	#define bp_heads(t)             (* (u8_t *)  (&(t)[2]))
 10911	#define bp_reduced_wr(t)        (* (u16_t *) (&(t)[3]))
 10912	#define bp_precomp(t)           (* (u16_t *) (&(t)[5]))
 10913	#define bp_max_ecc(t)           (* (u8_t *)  (&(t)[7]))
 10914	#define bp_ctlbyte(t)           (* (u8_t *)  (&(t)[8]))
 10915	#define bp_landingzone(t)       (* (u16_t *) (&(t)[12]))
 10916	#define bp_sectors(t)           (* (u8_t *)  (&(t)[14]))
 10917	
 10918	/* Разное. */
 10919	#define DEV_PER_DRIVE   (1 + NR_PARTITIONS)
 10920	#define MINOR_t0        64
 10921	#define MINOR_r0        120
 10922	#define MINOR_d0p0s0    128
 10923	#define MINOR_fd0p0     (28<<2)
 10924	#define P_FLOPPY        0
 10925	#define P_PRIMARY       1
 10926	#define P_SUB           2




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      drivers/libdriver/driver.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 11000	/* Этот файл содержит интерфейс драйверов устройств, независимый от устройств.
 11001	 *
 11002	 * Изменения: 
 11003	 *   25 июля 2005:   добавлен тип сигналов SYS_SIG (Jorrit N. Herder)
 11004	 *   15 сентября 2004:   добавлен тип SYN_ALARM для таймаутов  (Jorrit N. Herder)
 11005	 *   23 июля 2004:   удалены зависимости от ядра (Jorrit N. Herder)
 11006	 *   02 апреля 1992:   создан из драйверов at_wini и дискеты  (Kees J. Bot)
 11007	 *
 11008	 *
 11009	 * Драйверы поддерживают следующие операции:  (с помощью формата сообщений m2): 
 11010	 *
 11011	 *    m_type        DEVICE      PROC_NR                COUNT     POSITION     ADRRESS
 11012	 * ---------------------------------------------------------------------------------------
 11013	 * |  DEV_OPEN  | устройство | номер процедуры |                |         |              |
 11014	 * |------------+------------+-----------------+----------------+---------+--------------|
 11015	 * |  DEV_CLOSE | устройство | номер процедуры |                |         |              |
 11016	 * |------------+------------+-----------------+----------------+---------+--------------|
 11017	 * |  DEV_READ  | устройство | номер процедуры |     байты      | смещение| ук-ль буфера |
 11018	 * |------------+------------+-----------------+----------------+---------+--------------|
 11019	 * |  DEV_WRITE | устройство | номер процедуры |     байты      | смещение| ук-ль буфера |
 11020	 * |------------+------------+-----------------+----------------+---------+--------------|
 11021	 * | DEV_GATHER | устройство | номер процедуры | длина вектора  | смещение| ук-ль буфера |
 11022	 * |------------+------------+-----------------+----------------+---------+--------------|
 11023	 * | DEV_SCATTER| устройство | номер процедуры | длина вектора  | смещение| ук-ль буфера |
 11024	 * |------------+------------+-----------------+----------------+---------+--------------|
 11025	 * |  DEV_IOCTL | устройство | номер процедуры |  код функции   |         | ук-ль буфера |
 11026	 * |------------+------------+-----------------+----------------+---------+--------------|
 11027	 * |  CANCEL    | устройство | номер процедуры | чтение/запись  |         |              |
 11028	 * |------------+------------+-----------------+----------------+---------+--------------|
 11029	 * |  HARD_STOP |            |                 |                |         |              |
 11030	 * ---------------------------------------------------------------------------------------
 11031	 *
 11032	 * Файл содержит одну точку входа : 
 11033	 *
 11034	 *   driver_task:        вызывается записью задания, зависимого от устройства
 11035	 */
 11036	
 11037	#include "../drivers.h"
 11038	#include <sys/ioc_disk.h>
 11039	#include "driver.h"
 11040	
 11041	#define BUF_EXTRA       0
 11042	
 11043	/* резервирование места под переменные. */
 11044	PRIVATE u8_t buffer[(unsigned) 2 * DMA_BUF_SIZE + BUF_EXTRA];
 11045	u8_t *tmp_buf;                  /* DMA-буфер */
 11046	phys_bytes tmp_phys;            /* физический адрес DMA-буфера */
 11047	
 11048	FORWARD _PROTOTYPE( void init_buffer, (void) );
 11049	FORWARD _PROTOTYPE( int do_rdwt, (struct driver *dr, message *mp) );
 11050	FORWARD _PROTOTYPE( int do_vrdwt, (struct driver *dr, message *mp) );
 11051	
 11052	int device_caller;
 11053	
 11054	/*===========================================================================*
 11055	 *                              driver_task                                  *
 11056	 *===========================================================================*/
 11057	PUBLIC void driver_task(dp)
 11058	struct driver *dp;      /* Точки входа, зависимые от устройств. */
 11059	{
 11060	/* Главная программа каждого задания драйвера устройства. */
 11061	
 11062	  int r, proc_nr;
 11063	  message mess;
 11064	
 11065	  /* Получение DMA-буфера. */
 11066	  init_buffer();
 11067	
 11068	  /* Главный цикл задания диска. Он ожидает сообщения, обрабатывает его и посылает
 11069	   * ответ.
 11070	   */
 11071	  while (TRUE) {
 11072	
 11073	        /* Ожидание запроса на чтение или запись дискового блока. */
 11074	        if(receive(ANY, &mess) != OK) continue;
 11075	
 11076	        device_caller = mess.m_source;
 11077	        proc_nr = mess.PROC_NR;
 11078	
 11079	        /* Выполнение работы. */
 11080	        switch(mess.m_type) {
 11081	        case DEV_OPEN:           r = (*dp->dr_open)(dp, &mess);  break;
 11082	        case DEV_CLOSE:          r = (*dp->dr_close)(dp, &mess); break;
 11083	        case DEV_IOCTL:          r = (*dp->dr_ioctl)(dp, &mess); break;
 11084	        case CANCEL:             r = (*dp->dr_cancel)(dp, &mess);break;
 11085	        case DEV_SELECT:         r = (*dp->dr_select)(dp, &mess);break;
 11086	
 11087	        case DEV_READ:   
 11088	        case DEV_WRITE:    r = do_rdwt(dp, &mess);       break;
 11089	        case DEV_GATHER:  
 11090	        case DEV_SCATTER:  r = do_vrdwt(dp, &mess);      break;
 11091	
 11092	        case HARD_INT:           /* оставшееся прерывание истекшего таймера. */
 11093	                                if(dp->dr_hw_int) {
 11094	                                        (*dp->dr_hw_int)(dp, &mess);
 11095	                                }
 11096	                                continue;
 11097	        case SYS_SIG:            (*dp->dr_signal)(dp, &mess);
 11098	                                continue;       /* не отвечать */
 11099	        case SYN_ALARM:          (*dp->dr_alarm)(dp, &mess);     
 11100	                                continue;       /* не отвечать */
 11101	        default:                 
 11102	                if(dp->dr_other)
 11103	                        r = (*dp->dr_other)(dp, &mess);
 11104	                else    
 11105	                        r = EINVAL;
 11106	                break;
 11107	        }
 11108	
 11109	        /* Очистка "остаточного" состояния. */
 11110	        (*dp->dr_cleanup)();
 11111	
 11112	        /* Подготовка и передача ответного сообщения. */
 11113	        if (r != EDONTREPLY) {
 11114	                mess.m_type = TASK_REPLY;
 11115	                mess.REP_PROC_NR = proc_nr;
 11116	                /* Состояние – это число # переданных байтов или код ошибки. */
 11117	                mess.REP_STATUS = r;    
 11118	                send(device_caller, &mess);
 11119	        }
 11120	  }
 11121	}
	
 11123	/*===========================================================================*
 11124	 *                              init_buffer                                  *
 11125	 *===========================================================================*/
 11126	PRIVATE void init_buffer()
 11127	{
 11128	/* Выбор буфера, который может безопасно использоваться для DMA-передач. Он также может
 11129	 * применяться для чтения таблиц разделов и т. п. Его абсолютный адрес - 'tmp_phys', а
 11130	 * обычный адрес - 'tmp_buf'.
 11131	 */
 11132	
 11133	  unsigned left;
 11134	
 11135	  tmp_buf = buffer;
 11136	  sys_umap(SELF, D, (vir_bytes)buffer, (phys_bytes)sizeof(buffer), &tmp_phys);
 11137	
 11138	  if ((left = dma_bytes_left(tmp_phys)) < DMA_BUF_SIZE) {
 11139	        /* Первая половина буфера пересекает границу 64K, в нее нельзя обращаться напрямую */
 11140	        tmp_buf += left;
 11141	        tmp_phys += left;
 11142	  }
 11143	}
	
 11145	/*===========================================================================*
 11146	 *                              do_rdwt                                      *
 11147	 *===========================================================================*/
 11148	PRIVATE int do_rdwt(dp, mp)
 11149	struct driver *dp;              /* точки входа, зависимые от устройств */
 11150	message *mp;                    /* указатель для чтения и записи сообщения */
 11151	{
 11152	/* Обслуживание одного запроса чтения и записи. */
 11153	  iovec_t iovec1;
 11154	  int r, opcode;
 11155	  phys_bytes phys_addr;
 11156	
 11157	  /* Каковы дисковый адрес, адрес и длина буфера пользователя? */
 11158	  if (mp->COUNT < 0) return(EINVAL);
 11159	
 11160	  /* Проверка буфера пользователя. */
 11161	  sys_umap(mp->PROC_NR, D, (vir_bytes) mp->ADDRESS, mp->COUNT, &phys_addr);
 11162	  if (phys_addr == 0) return(EFAULT);
 11163	
 11164	  /* Подготовка к вводу-выводу. */
 11165	  if ((*dp->dr_prepare)(mp->DEVICE) == NIL_DEV) return(ENXIO);
 11166	
 11167	  /* Создание одноэлементного вектора разрозненного/объединенного ввода-вывода для буфера. */
 11168	  opcode = mp->m_type == DEV_READ ? DEV_GATHER :  DEV_SCATTER;
 11169	  iovec1.iov_addr = (vir_bytes) mp->ADDRESS;
 11170	  iovec1.iov_size = mp->COUNT;
 11171	
 11172	  /* Передача байтов с устройства и на устройство. */
 11173	  r = (*dp->dr_transfer)(mp->PROC_NR, opcode, mp->POSITION, &iovec1, 1);
 11174	
 11175	  /* Возврат числа переданных байтов или кода ошибки. */
 11176	  return(r == OK ? (mp->COUNT - iovec1.iov_size) :  r);
 11177	}
	
 11179	/*==========================================================================*
 11180	 *                              do_vrdwt                                    *
 11181	 *==========================================================================*/
 11182	PRIVATE int do_vrdwt(dp, mp)
 11183	struct driver *dp;      /* точки входа, зависимые от устройств */
 11184	message *mp;            /* указатель для чтения и записи сообщения */
 11185	{
 11186	/* Выполнение чтения из вектора пользовательских адресов или записи в вектор. Пользовательские
 11187	 * адреса считаются безопасными, то есть файловая система ведет обмен с использованием
 11188	 * собственных буферов, которые не проверяются.
 11189	 */
 11190	  static iovec_t iovec[NR_IOREQS];
 11191	  iovec_t *iov;
 11192	  phys_bytes iovec_size;
 11193	  unsigned nr_req;
 11194	  int r;
 11195	
 11196	  nr_req = mp->COUNT;   /* длина вектора ввода-вывода */
 11197	
 11198	  if (mp->m_source < 0) {
 11199	    /* вызывается заданием, копирование вектора не требуется. */
 11200	    iov = (iovec_t *) mp->ADDRESS;
 11201	  } else {
 11202	    /* копирование вектора из пространства запрашивающего процесса в пространство ядра. */
 11203	    if (nr_req > NR_IOREQS) nr_req = NR_IOREQS;
 11204	    iovec_size = (phys_bytes) (nr_req * sizeof(iovec[0]));
 11205	
 11206	    if (OK != sys_datacopy(mp->m_source, (vir_bytes) mp->ADDRESS, 
 11207	                SELF, (vir_bytes) iovec, iovec_size))
 11208	        panic((*dp->dr_name)(),"bad I/O vector by", mp->m_source);
 11209	    iov = iovec;
 11210	  }
 11211	
 11212	  /* Подготовка к вводу-выводу. */
 11213	  if ((*dp->dr_prepare)(mp->DEVICE) == NIL_DEV) return(ENXIO);
 11214	
 11215	  /* Передача байт с/на устройство. */
 11216	  r = (*dp->dr_transfer)(mp->PROC_NR, mp->m_type, mp->POSITION, iov, nr_req);
 11217	
 11218	  /* Копирование вектора ввода-вывода обратно в запрашивающий процесс. */
 11219	  if (mp->m_source >= 0) {
 11220	    sys_datacopy(SELF, (vir_bytes) iovec, 
 11221	        mp->m_source, (vir_bytes) mp->ADDRESS, iovec_size);
 11222	  }
 11223	  return(r);
 11224	}
	
 11226	/*===========================================================================*
 11227	 *                              no_name                                      *
 11228	 *===========================================================================*/
 11229	PUBLIC char *no_name()
 11230	{
 11231	/* Используйте это имя по умолчанию, если у устройства нет собственного имени. Изначально
 11232	 * имя процесса извлекалось из таблицы заданий:
 11233	 * "return(tasktab[proc_number(proc_ptr) + NR_TASKS].name);", однако сейчас возвращается
 11234	 * "noname". Возможно, в будущем для получения имени можно будет опросить какую-нибудь 
 11235	 * службу системной информации.
 11236	 */
 11237	  static char name[] = "noname";
 11238	  return name;
 11239	}
	
 11241	/*============================================================================*
 11242	 *                              do_nop                                        *
 11243	 *============================================================================*/
 11244	PUBLIC int do_nop(dp, mp)
 11245	struct driver *dp;
 11246	message *mp;
 11247	{
 11248	/* Ничего нет или нечего делать. */
 11249	
 11250	  switch (mp->m_type) {
 11251	  case DEV_OPEN:         return(ENODEV);
 11252	  case DEV_CLOSE:        return(OK);
 11253	  case DEV_IOCTL:        return(ENOTTY);
 11254	  default:               return(EIO);
 11255	  }
 11256	}
	
 11258	/*============================================================================*
 11259	 *                              nop_signal                                    *
 11260	 *============================================================================*/
 11261	PUBLIC void nop_signal(dp, mp)
 11262	struct driver *dp;
 11263	message *mp;
 11264	{
 11265	/* По умолчанию сигнал игнорируется. */
 11266	}
	
 11268	/*============================================================================*
 11269	 *                              nop_alarm                                     *
 11270	 *============================================================================*/
 11271	PUBLIC void nop_alarm(dp, mp)
 11272	struct driver *dp;
 11273	message *mp;
 11274	{
 11275	/* Игнорирование остатка уведомления. */
 11276	}
	
 11278	/*===========================================================================*
 11279	 *                              nop_prepare                                  *
 11280	 *===========================================================================*/
 11281	PUBLIC struct device *nop_prepare(device)
 11282	{
 11283	/* Не к чему готовиться. */
 11284	  return(NIL_DEV);
 11285	}
	
 11287	/*===========================================================================*
 11288	 *                              nop_cleanup                                  *
 11289	 *===========================================================================*/
 11290	PUBLIC void nop_cleanup()
 11291	{
 11292	/* Нечего очищать. */
 11293	}
	
 11295	/*===========================================================================*
 11296	 *                              nop_cancel                                   *
 11297	 *===========================================================================*/
 11298	PUBLIC int nop_cancel(struct driver *dr, message *m)
 11299	{
 11300	/* Нечего отменять. */
 11301	   return(OK);
 11302	}
	
 11304	/*===========================================================================*
 11305	 *                              nop_select                                   *
 11306	 *===========================================================================*/
 11307	PUBLIC int nop_select(struct driver *dr, message *m)
 11308	{
 11309	/* Нечего выбрать. */
 11310	   return(OK);
 11311	}
	
 11313	/*============================================================================*
 11314	 *                              do_diocntl                                    *
 11315	 *============================================================================*/
 11316	PUBLIC int do_diocntl(dp, mp)
 11317	struct driver *dp;
 11318	message *mp;                    /* указатель на ioctl-запрос */
 11319	{
 11320	/* Выполнение запроса на установку/получение раздела. */
 11321	  struct device *dv;
 11322	  struct partition entry;
 11323	  int s;
 11324	
 11325	  if (mp->REQUEST != DIOCSETP && mp->REQUEST != DIOCGETP) {
 11326	        if(dp->dr_other) {
 11327	                return dp->dr_other(dp, mp);
 11328	        } else return(ENOTTY);
 11329	  }
 11330	
 11331	  /* Декодирование параметров сообщения. */
 11332	  if ((dv = (*dp->dr_prepare)(mp->DEVICE)) == NIL_DEV) return(ENXIO);
 11333	
 11334	  if (mp->REQUEST == DIOCSETP) {
 11335	        /* Копирование этой записи таблицы разделов. */
 11336	        if (OK != (s=sys_datacopy(mp->PROC_NR, (vir_bytes) mp->ADDRESS,
 11337	                SELF, (vir_bytes) &entry, sizeof(entry))))
 11338	            return s;
 11339	        dv->dv_base = entry.base;
 11340	        dv->dv_size = entry.size;
 11341	  } else {
 11342	        /* Возврат записи таблицы разделов и геометрии диска. */
 11343	        entry.base = dv->dv_base;
 11344	        entry.size = dv->dv_size;
 11345	        (*dp->dr_geometry)(&entry);
 11346	        if (OK != (s=sys_datacopy(SELF, (vir_bytes) &entry,
 11347	                mp->PROC_NR, (vir_bytes) mp->ADDRESS, sizeof(entry))))
 11348	            return s;
 11349	  }
 11350	  return(OK);
 11351	}


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      drivers/libdriver/drvlib.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 11400	/* Служебные функции драйверов устройств IBM.                 Автор:  Kees J. Bot
 11401	 *                                                            7 декабря 1995
 11402	 * Точка входа: 
 11403	 *   partition:  создание разделов на диске согласно таблице(-ам) разделов.
 11404	 */
 11405	
 11406	#include "driver.h"
 11407	#include "drvlib.h"
 11408	#include <unistd.h>
 11409	
 11410	/* Является ли раздел расширенным? */
 11411	#define ext_part(s)     ((s) == 0x05 || (s) == 0x0F)
 11412	
 11413	FORWARD _PROTOTYPE( void extpartition, (struct driver *dp, int extdev,
 11414	                                                unsigned long extbase) );
 11415	FORWARD _PROTOTYPE( int get_part_table, (struct driver *dp, int device,
 11416	                        unsigned long offset, struct part_entry *table));
 11417	FORWARD _PROTOTYPE( void sort, (struct part_entry *table) );
 11418	
 11419	#ifndef CD_SECTOR_SIZE
 11420	#define CD_SECTOR_SIZE 2048
 11421	#endif 
 11422	
 11423	/*============================================================================*
 11424	 *                              partition                                     *
 11425	 *============================================================================*/
 11426	PUBLIC void partition(dp, device, style, atapi)
 11427	struct driver *dp;      /* точки входа, зависимые от устройств */
 11428	int device;             /* разбиваемое на разделы устройство */
 11429	int style;              /* стиль раздела: дискетный, главный, подраздел. */
 11430	int atapi;              /* atapi-устройство */
 11431	{
 11432	/* Эта процедура вызывается при первом открытии устройства для инициализации таблиц
 11433	 * его разделов. Процедура проверяет, что каждый раздел полностью входит в пределы
 11434	 * устройства. В зависимости от стиля раздела создаются разделы дискет, главные
 11435	 * разделы либо подразделы. Сортировке подлежат только главные подразделы, поскольку
 11436	 * они используются совместно с другими операционными системами, которые рассчитаны на
 11437	 * такую сортировку.
 11438	 */
 11439	  struct part_entry table[NR_PARTITIONS], *pe;
 11440	  int disk, par;
 11441	  struct device *dv;
 11442	  unsigned long base, limit, part_limit;
 11443	
 11444	  /* Получение геометрии разбиваемого на разделы устройства */
 11445	  if ((dv = (*dp->dr_prepare)(device)) == NIL_DEV
 11446	                                || cmp64u(dv->dv_size, 0) == 0) return;
 11447	  base = div64u(dv->dv_base, SECTOR_SIZE);
 11448	  limit = base + div64u(dv->dv_size, SECTOR_SIZE);
 11449	
 11450	  /* Чтение таблицы разделов устройства. */
 11451	  if(!get_part_table(dp, device, 0L, table)) {
 11452	          return;
 11453	  }
 11454	
 11455	  /* Вычисление номера устройства для первого раздела . */
 11456	  switch (style) {
 11457	  case P_FLOPPY: 
 11458	        device += MINOR_fd0p0;
 11459	        break;
 11460	  case P_PRIMARY: 
 11461	        sort(table);            /* сортировка таблицы главных разделов */
 11462	        device += 1;
 11463	        break;
 11464	  case P_SUB: 
 11465	        disk = device / DEV_PER_DRIVE;
 11466	        par = device % DEV_PER_DRIVE - 1;
 11467	        device = MINOR_d0p0s0 + (disk * NR_PARTITIONS + par) * NR_PARTITIONS;
 11468	  }
 11469	
 11470	  /* Поиск массива устройств. */
 11471	  if ((dv = (*dp->dr_prepare)(device)) == NIL_DEV) return;
 11472	
 11473	  /* Задание геометрии разделов из таблицы разделов. */
 11474	  for (par = 0; par < NR_PARTITIONS; par++, dv++) {
 11475	        /* сжатие раздела для того, чтобы целиком разместить его на устройстве. */
 11476	        pe = &table[par];
 11477	        part_limit = pe->lowsec + pe->size;
 11478	        if (part_limit < pe->lowsec) part_limit = limit;
 11479	        if (part_limit > limit) part_limit = limit;
 11480	        if (pe->lowsec < base) pe->lowsec = base;
 11481	        if (part_limit < pe->lowsec) part_limit = pe->lowsec;
 11482	
 11483	        dv->dv_base = mul64u(pe->lowsec, SECTOR_SIZE);
 11484	        dv->dv_size = mul64u(part_limit - pe->lowsec, SECTOR_SIZE);
 11485	
 11486	        if (style == P_PRIMARY) {
 11487	                /* Каждый главный раздел Minix может быть разбит на подразделы. */
 11488	                if (pe->sysind == MINIX_PART)
 11489	                        partition(dp, device + par, P_SUB, atapi);
 11490	
 11491	                /* Расширенный раздел имеет логические разделы. */
 11492	                if (ext_part(pe->sysind))
 11493	                        extpartition(dp, device + par, pe->lowsec);
 11494	        }
 11495	  }
 11496	}
	
 11498	/*============================================================================*
 11499	 *                              extpartition                                  *
 11500	 *============================================================================*/
 11501	PRIVATE void extpartition(dp, extdev, extbase)
 11502	struct driver *dp;      /* точки входа, зависимые от устройств */
 11503	int extdev;             /* расширенный раздел для сканирования */
 11504	unsigned long extbase;  /* секторное смещение базового адреса расширенного раздела */
 11505	{
 11506	/* Расширенные разделы не могут быть проигнорированы, поскольку пользователям нужно 
 11507	 * перемещать файлы с DOS-разделов и на DOS-разделы. Не читайте код – ничего приятного в нем нет.
 11508	 */
 11509	  struct part_entry table[NR_PARTITIONS], *pe;
 11510	  int subdev, disk, par;
 11511	  struct device *dv;
 11512	  unsigned long offset, nextoffset;
 11513	
 11514	  disk = extdev / DEV_PER_DRIVE;
 11515	  par = extdev % DEV_PER_DRIVE - 1;
 11516	  subdev = MINOR_d0p0s0 + (disk * NR_PARTITIONS + par) * NR_PARTITIONS;
 11517	
 11518	  offset = 0;
 11519	  do {
 11520	        if (!get_part_table(dp, extdev, offset, table)) return;
 11521	        sort(table);
 11522	
 11523	        /* Таблица должна содержать один логический раздел и, возможно, еще один
 11524	         * расширенный раздел. (Это связанный список.)
 11525	         */
 11526	        nextoffset = 0;
 11527	        for (par = 0; par < NR_PARTITIONS; par++) {
 11528	                pe = &table[par];
 11529	                if (ext_part(pe->sysind)) {
 11530	                        nextoffset = pe->lowsec;
 11531	                } else
 11532	                if (pe->sysind != NO_PART) {
 11533	                        if ((dv = (*dp->dr_prepare)(subdev)) == NIL_DEV) return;
 11534	
 11535	                        dv->dv_base = mul64u(extbase + offset + pe->lowsec,
 11536	                                                                SECTOR_SIZE);
 11537	                        dv->dv_size = mul64u(pe->size, SECTOR_SIZE);
 11538	
 11539	                        /* нет устройств? */
 11540	                        if (++subdev % NR_PARTITIONS == 0) return;
 11541	                }
 11542	        }
 11543	  } while ((offset = nextoffset) != 0);
 11544	}
	
 11546	/*============================================================================*
 11547	 *                              get_part_table                                *
 11548	 *============================================================================*/
 11549	PRIVATE int get_part_table(dp, device, offset, table)
 11550	struct driver *dp;
 11551	int device;
 11552	unsigned long offset;           /* секторное смещение таблицы */
 11553	struct part_entry *table;       /* четыре записи */
 11554	{
 11555	/* Чтение таблицы разделов устройств, возврат true
 11556	 * при отсутствии ошибок.
 11557	 */
 11558	  iovec_t iovec1;
 11559	  off_t position;
 11560	  static unsigned char partbuf[CD_SECTOR_SIZE];
 11561	
 11562	  position = offset << SECTOR_SHIFT;
 11563	  iovec1.iov_addr = (vir_bytes) partbuf;
 11564	  iovec1.iov_size = CD_SECTOR_SIZE;
 11565	  if ((*dp->dr_prepare)(device) != NIL_DEV) {
 11566	        (void) (*dp->dr_transfer)(SELF, DEV_GATHER, position, &iovec1, 1);
 11567	  }
 11568	  if (iovec1.iov_size != 0) {
 11569	        return 0;
 11570	  }
 11571	  if (partbuf[510] != 0x55 || partbuf[511] != 0xAA) {
 11572	        /* Некорректная таблица разделов. */
 11573	        return 0;
 11574	  }
 11575	  memcpy(table, (partbuf + PART_TABLE_OFF), NR_PARTITIONS * sizeof(table[0]));
 11576	  return 1;
 11577	}
	
 11579	/*===========================================================================*
 11580	 *                              sort                                         *
 11581	 *===========================================================================*/
 11582	PRIVATE void sort(table)
 11583	struct part_entry *table;
 11584	{
 11585	/* Сортировка таблицы разделов. */
 11586	  struct part_entry *pe, tmp;
 11587	  int n = NR_PARTITIONS;
 11588	
 11589	  do {
 11590	        for (pe = table; pe < table + NR_PARTITIONS-1; pe++) {
 11591	                if (pe[0].sysind == NO_PART
 11592	                        || (pe[0].lowsec > pe[1].lowsec
 11593	                                        && pe[1].sysind != NO_PART)) {
 11594	                        tmp = pe[0]; pe[0] = pe[1]; pe[1] = tmp;
 11595	                }
 11596	        }
 11597	  } while (--n > 0);
 11598	}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      drivers/memory/memory.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 11600	/* Этот файл содержит часть драйверов, зависимую от устройств, для следующих специальных
 11601	 * файлов: 
 11602	 *     /dev/ram         - виртуальный диск
 11603	 *     /dev/mem         - абсолютная память
 11604	 *     /dev/kmem        - виртуальная память ядра
 11605	 *     /dev/null        - нуль-устройство (приемник данных)
 11606	 *     /dev/boot        - загрузочное устройство, загружаемое из загрузочного образа
 11607	 *     /dev/zero        - генератор потока нулевых байтов
 11608	 *
 11609	 *  Изменения: 
 11610	 *      29 апреля 2005:    добавлен генератор нулевых байтов (Jorrit N. Herder)
 11611	 *      09 апреля 2005:    добавлена поддержка загрузочного устройства (Jorrit N. Herder)
 11612	 *      26 июля 2004:      драйвер виртуального диска перемещен в пространство пользователя (Jorrit N. Herder)
 11613	 *      20 апреля 1992:    разделение кода на зависимый и независимый от устройств  (Kees J. Bot)
 11614	 */
 11615	
 11616	#include "../drivers.h"
 11617	#include "../libdriver/driver.h"
 11618	#include <sys/ioc_memory.h>
 11619	#include "../../kernel/const.h"
 11620	#include "../../kernel/config.h"
 11621	#include "../../kernel/type.h"
 11622	
 11623	#include "assert.h"
 11624	
 11625	#define NR_DEVS            6            /* номера вспомогательных устройств */
 11626	
 11627	PRIVATE struct device m_geom[NR_DEVS];  /* базовый адрес и размер каждого устройства */
 11628	PRIVATE int m_seg[NR_DEVS];             /* сегментный индекс каждого устройства */
 11629	PRIVATE int m_device;                   /* текущее устройство */
 11630	PRIVATE struct kinfo kinfo;             /* информация о ядре */ 
 11631	PRIVATE struct machine machine;         /* информация о компьютере */ 
 11632	
 11633	extern int errno;                       /* номер ошибки для вызовов менеджера процессов */
 11634	
 11635	FORWARD _PROTOTYPE( char *m_name, (void)                                );
 11636	FORWARD _PROTOTYPE( struct device *m_prepare, (int device)              );
 11637	FORWARD _PROTOTYPE( int m_transfer, (int proc_nr, int opcode, off_t position,
 11638	                                        iovec_t *iov, unsigned nr_req)  );
 11639	FORWARD _PROTOTYPE( int m_do_open, (struct driver *dp, message *m_ptr)  );
 11640	FORWARD _PROTOTYPE( void m_init, (void) );
 11641	FORWARD _PROTOTYPE( int m_ioctl, (struct driver *dp, message *m_ptr)    );
 11642	FORWARD _PROTOTYPE( void m_geometry, (struct partition *entry)          );
 11643	
 11644	/* Точки входа в этот драйвер. */
 11645	PRIVATE struct driver m_dtab = {
 11646	  m_name,       /* имя текущего устройства */
 11647	  m_do_open,    /* открытие или монтирование */
 11648	  do_nop,       /* отсутствие действий при закрытии устройства */
 11649	  m_ioctl,      /* задание геометрии виртуального диска */
 11650	  m_prepare,    /* подготовка к вводу-выводу на заданное вспомогательное устройство */
 11651	  m_transfer,   /* выполнение ввода-вывода */
 11652	  nop_cleanup,  /* очистка не требуется */
 11653	  m_geometry,   /* "geometry" устройства памяти */
 11654	  nop_signal,   /* системные сигналы */
 11655	  nop_alarm,
 11656	  nop_cancel,
 11657	  nop_select,
 11658	  NULL,
 11659	  NULL
 11660	};
 11661	
 11662	/* Буфер для потока нулевых байтов устройства /dev/zero. */
 11663	#define ZERO_BUF_SIZE                   1024
 11664	PRIVATE char dev_zero[ZERO_BUF_SIZE];
 11665	
 11666	#define click_to_round_k(n) \
 11667	        ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
 11668	
 11669	/*===========================================================================*
 11670	 *                                 main                                      *
 11671	 *===========================================================================*/
 11672	PUBLIC int main(void)
 11673	{
 11674	/* Главная программа. Инициализация драйвера памяти и запуск главного цикла. */
 11675	  m_init();                     
 11676	  driver_task(&m_dtab);         
 11677	  return(OK);                           
 11678	}
	
 11680	/*===========================================================================*
 11681	 *                               m_name                                      *
 11682	 *===========================================================================*/
 11683	PRIVATE char *m_name()
 11684	{
 11685	/* Возврат имени текущего устройства. */
 11686	  static char name[] = "memory";
 11687	  return name;  
 11688	}
	
 11690	/*===========================================================================*
 11691	 *                              m_prepare                                    *
 11692	 *===========================================================================*/
 11693	PRIVATE struct device *m_prepare(device)
 11694	int device;
 11695	{
 11696	/* Подготовка ввода-вывода на устройство: проверка, корректен ли вспомогательный номер устройства. */
 11697	  if (device < 0 || device >= NR_DEVS) return(NIL_DEV);
 11698	  m_device = device;
 11699	
 11700	  return(&m_geom[device]);
 11701	}
	
 11703	/*===========================================================================*
 11704	 *                              m_transfer                                   *
 11705	 *===========================================================================*/
 11706	PRIVATE int m_transfer(proc_nr, opcode, position, iov, nr_req)
 11707	int proc_nr;                    /* запрашивающий процесс */
 11708	int opcode;                     /* DEV_GATHER или DEV_SCATTER */
 11709	off_t position;                 /* смещение на устройстве, по которому выполняется операция */
 11710	iovec_t *iov;                   /* указатель на вектор чтения или записи */
 11711	unsigned nr_req;                /* длина вектора запросов */
 11712	{
 11713	/* Чтение или записть на одно из вспомогательных устройств драйвера. */
 11714	  phys_bytes mem_phys;
 11715	  int seg;
 11716	  unsigned count, left, chunk;
 11717	  vir_bytes user_vir;
 11718	  struct device *dv;
 11719	  unsigned long dv_size;
 11720	  int s;
 11721	
 11722	  /* Получение номера вспомогательного устройства и проверка, является ли устройство /dev/null. */
 11723	  dv = &m_geom[m_device];
 11724	  dv_size = cv64ul(dv->dv_size);
 11725	
 11726	  while (nr_req > 0) {
 11727	
 11728	        /* Число передаваемых байтов и направление передачи. */
 11729	        count = iov->iov_size;
 11730	        user_vir = iov->iov_addr;
 11731	
 11732	        switch (m_device) {
 11733	
 11734	        /* Копирования нет; игнорирование запроса. */
 11735	        case NULL_DEV: 
 11736	            if (opcode == DEV_GATHER) return(OK);       /* всегда в конце файла */
 11737	            break;
 11738	
 11739	        /* Виртуальное копирование для виртуального диска, памяти ядра и загрузочного устройства. */
 11740	        case RAM_DEV: 
 11741	        case KMEM_DEV: 
 11742	        case BOOT_DEV: 
 11743	            if (position >= dv_size) return(OK);        /* проверка конца файла */
 11744	            if (position + count > dv_size) count = dv_size - position;
 11745	            seg = m_seg[m_device];
 11746	
 11747	            if (opcode == DEV_GATHER) {                 /* копирование фактических данных */
 11748	                sys_vircopy(SELF,seg,position, proc_nr,D,user_vir, count);
 11749	            } else {
 11750	                sys_vircopy(proc_nr,D,user_vir, SELF,seg,position, count);
 11751	            }
 11752	            break;
 11753	
 11754	        /* Физическое копирование. Используется только для доступа ко всей памяти. */
 11755	        case MEM_DEV: 
 11756	            if (position >= dv_size) return(OK);        /* проверка конца файла */
 11757	            if (position + count > dv_size) count = dv_size - position;
 11758	            mem_phys = cv64ul(dv->dv_base) + position;
 11759	
 11760	            if (opcode == DEV_GATHER) {                 /* копирование данных */
 11761	                sys_physcopy(NONE, PHYS_SEG, mem_phys, 
 11762	                        proc_nr, D, user_vir, count);
 11763	            } else {
 11764	                sys_physcopy(proc_nr, D, user_vir, 
 11765	                        NONE, PHYS_SEG, mem_phys, count);
 11766	            }
 11767	            break;
 11768	
 11769	        /* Генератор потока нулевых байтов. */
 11770	        case ZERO_DEV: 
 11771	            if (opcode == DEV_GATHER) {
 11772	                left = count;
 11773	                while (left > 0) {
 11774	                    chunk = (left > ZERO_BUF_SIZE) ? ZERO_BUF_SIZE :  left;
 11775	                    if (OK != (s=sys_vircopy(SELF, D, (vir_bytes) dev_zero, 
 11776	                            proc_nr, D, user_vir, chunk)))
 11777	                        report("MEM","sys_vircopy failed", s);
 11778	                    left -= chunk;
 11779	                    user_vir += chunk;
 11780	                }
 11781	            }
 11782	            break;
 11783	
 11784	        /* Неизвестное (недопустимое) вспомогательное устройство. */
 11785	        default: 
 11786	            return(EINVAL);
 11787	        }
 11788	
 11789	        /* учет числа переданных байтов. */
 11790	        position += count;
 11791	        iov->iov_addr += count;
 11792	        if ((iov->iov_size -= count) == 0) { iov++; nr_req--; }
 11793	
 11794	  }
 11795	  return(OK);
 11796	}
	
 11798	/*===========================================================================*
 11799	 *                              m_do_open                                    *
 11800	 *===========================================================================*/
 11801	PRIVATE int m_do_open(dp, m_ptr)
 11802	struct driver *dp;
 11803	message *m_ptr;
 11804	{
 11805	/* Проверка номера устройства при открытии. (это делается для того, чтобы дать привилегии 
 11806	 * процессу, открывающему /dev/mem или /dev/kmem. Это может понадобиться при вводе-выводе
 11807	 * с отображением в память. Для ввода-вывода с помощью системных вызовов это больше не нужно.)
 11808	 */
 11809	  if (m_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
 11810	
 11811	  return(OK);
 11812	}
	
 11814	/*===========================================================================*
 11815	 *                              m_init                                       *
 11816	 *===========================================================================*/
 11817	PRIVATE void m_init()
 11818	{
 11819	  /* Инициализация этого задания. Все вспомогательные устройства инициализируются по одному. */
 11820	  int i, s;
 11821	
 11822	  if (OK != (s=sys_getkinfo(&kinfo))) {
 11823	      panic("MEM","Couldn't get kernel information.",s);
 11824	  }
 11825	
 11826	  /* Установка удаленного сегмента для памяти /dev/kmem. */
 11827	  m_geom[KMEM_DEV].dv_base = cvul64(kinfo.kmem_base);
 11828	  m_geom[KMEM_DEV].dv_size = cvul64(kinfo.kmem_size);
 11829	  if (OK != (s=sys_segctl(&m_seg[KMEM_DEV], (u16_t *) &s, (vir_bytes *) &s, 
 11830	                kinfo.kmem_base, kinfo.kmem_size))) {
 11831	      panic("MEM","Couldn't install remote segment.",s);
 11832	  }
 11833	
 11834	  /* Установка удаленного сегмента для памяти /dev/boot, если разрешено. */
 11835	  m_geom[BOOT_DEV].dv_base = cvul64(kinfo.bootdev_base);
 11836	  m_geom[BOOT_DEV].dv_size = cvul64(kinfo.bootdev_size);
 11837	  if (kinfo.bootdev_base > 0) {
 11838	      if (OK != (s=sys_segctl(&m_seg[BOOT_DEV], (u16_t *) &s, (vir_bytes *) &s, 
 11839	              kinfo.bootdev_base, kinfo.bootdev_size))) {
 11840	          panic("MEM","Couldn't install remote segment.",s);
 11841	      }
 11842	  }
 11843	
 11844	  /* Инициализация /dev/zero. Запись нулей в буфер. */
 11845	  for (i=0; i<ZERO_BUF_SIZE; i++) {
 11846	       dev_zero[i] = '\0';
 11847	  }
 11848	
 11849	  /* Установка диапазонов памяти для /dev/mem. */
 11850	  if (OK != (s=sys_getmachine(&machine))) {
 11851	      panic("MEM","Couldn't get machine information.",s);
 11852	  }
 11853	  if (! machine.protected) {
 11854	        m_geom[MEM_DEV].dv_size =   cvul64(0x100000); /* 1M for 8086 systems */
 11855	  } else {
 11856	        m_geom[MEM_DEV].dv_size = cvul64(0xFFFFFFFF); /* 4G-1 for 386 systems */
 11857	  }
 11858	}
	
 11860	/*===========================================================================*
 11861	 *                              m_ioctl                                      *
 11862	 *===========================================================================*/
 11863	PRIVATE int m_ioctl(dp, m_ptr)
 11864	struct driver *dp;                      /* указатель на структуру драйвера */
 11865	message *m_ptr;                         /* указатель на управляющее сообщение */
 11866	{
 11867	/* Управление вводом-выводом для драйвера памяти. В настоящий момент имеется только одно управляющее сообщение: 
 11868	 * - MIOCRAMSIZE:  задание размера виртуального диска.
 11869	 */
 11870	  struct device *dv;
 11871	  if ((dv = m_prepare(m_ptr->DEVICE)) == NIL_DEV) return(ENXIO);
 11872	
 11873	  switch (m_ptr->REQUEST) {
 11874	    case MIOCRAMSIZE:  {
 11875	        /* Файловая система собирается создать новый виртуальный диск заданного размера. */
 11876	        phys_bytes ramdev_size;
 11877	        phys_bytes ramdev_base;
 11878	        int s;
 11879	
 11880	        if (m_ptr->PROC_NR != FS_PROC_NR) {
 11881	            report("MEM", "warning, MIOCRAMSIZE called by", m_ptr->PROC_NR);
 11882	            return(EPERM);
 11883	        }
 11884	
 11885	        /* Попытка выделить область памяти для виртуального диска. */
 11886	        ramdev_size = m_ptr->POSITION;
 11887	        if (allocmem(ramdev_size, &ramdev_base) < 0) {
 11888	            report("MEM", "warning, allocmem failed", errno);
 11889	            return(ENOMEM);
 11890	        }
 11891	        dv->dv_base = cvul64(ramdev_base);
 11892	        dv->dv_size = cvul64(ramdev_size);
 11893	
 11894	        if (OK != (s=sys_segctl(&m_seg[RAM_DEV], (u16_t *) &s, (vir_bytes *) &s, 
 11895	                ramdev_base, ramdev_size))) {
 11896	                panic("MEM","Couldn't install remote segment.",s);
 11897	        }
 11898	        break;
 11899	    }
 11900	
 11901	    default: 
 11902	        return(do_diocntl(&m_dtab, m_ptr));
 11903	  }
 11904	  return(OK);
 11905	}
	
 11907	/*===========================================================================*
 11908	 *                              m_geometry                                   *
 11909	 *===========================================================================*/
 11910	PRIVATE void m_geometry(entry)
 11911	struct partition *entry;
 11912	{
 11913	  /* Устройства памяти не имеют геометрии, однако внешний мир настаивает. */
 11914	  entry->cylinders = div64u(m_geom[m_device].dv_size, SECTOR_SIZE) / (64 * 32);
 11915	  entry->heads = 64;
 11916	  entry->sectors = 32;
 11917	}



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      drivers/at_wini/at_wini.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 12000	#include "../drivers.h"
 12001	#include "../libdriver/driver.h"
 12002	#include "../libdriver/drvlib.h"
 12003	
 12004	_PROTOTYPE(int main, (void));
 12005	
 12006	#define VERBOSE            0    /* отображение сообщений об идентификации при загрузке */
 12007	#define ENABLE_ATAPI    0       /* добавление в драйвер поддержки ATAPI cd-rom */



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      drivers/at_wini/at_wini.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 12100	/* Этот файл содержит зависимую от устройства часть драйвера контроллера жесткого диска
 12101	 * IBM-AT. Автор - Adri Koppes.
 12102	 *
 12103	 * Файл содержит одну точку входа: 
 12104	 *
 12105	 *   at_winchester_task:         главная точка входа при запуске системы
 12106	 *
 12107	 * Изменения: 
 12108	 *   19 августа 2005: поддержка ata pci и SATA  (Ben Gras)
 12109	 *   18 ноября 2004:  перемещение драйвера диска AT в пространство пользователя (Jorrit N. Herder)
 12110	 *   20 августа 2004: сторожевые функции заменены синхронными уведомлениями (Jorrit N. Herder)
 12111	 *   23 марта 2000:   добавлена поддержка ATAPI CDROM (Michael Temari)
 12112	 *   14 мая 2000:     переработка кода, зависимого и независимого от устройств (Kees J. Bot)
 12113	 *   13 апреля 1992:   разделение кода на зависимый и независимый от устройств  (Kees J. Bot)
 12114	 */
 12115	
 12116	#include "at_wini.h"
 12117	#include "../libpci/pci.h"
 12118	
 12119	#include <minix/sysutil.h>
 12120	#include <minix/keymap.h>
 12121	#include <sys/ioc_disk.h>
 12122	
 12123	#define ATAPI_DEBUG         0   /* Для отладки ATAPI-кода. */
 12124	
 12125	/* Порты ввода-вывода, используемые контроллерами жестких дисков. */
 12126	
 12127	/* Чтение и запись регистров */
 12128	#define REG_CMD_BASE0   0x1F0   /* базовый регистр команд контроллера 0 */
 12129	#define REG_CMD_BASE1   0x170   /* базовый регистр команд контроллера 1 */
 12130	#define REG_CTL_BASE0   0x3F6   /* базовый регистр управления контроллера 0 */
 12131	#define REG_CTL_BASE1   0x376   /* базовый регистр управления контроллера 1 */
 12132	
 12133	#define REG_DATA            0   /* регистр данных (смещение от базового регистра) */
 12134	#define REG_PRECOMP         1   /* начало предкомпенсации при записи */
 12135	#define REG_COUNT           2   /* секторы для передачи */
 12136	#define REG_SECTOR          3   /* номер сектора */
 12137	#define REG_CYL_LO          4   /* младший байт номера цилиндра */
 12138	#define REG_CYL_HI          5   /* старший байт номера цилиндра */
 12139	#define REG_LDH             6   /* логический адрес блока, диск и головка */
 12140	#define   LDH_DEFAULT           0xA0    /* включение ECC, 512 байт на сектор */
 12141	#define   LDH_LBA               0x40    /* Использование логической адресации блоков */
 12142	#define   ldh_init(drive)       (LDH_DEFAULT | ((drive) << 4))
 12143	
 12144	/* Регистры только для чтения */
 12145	#define REG_STATUS          7   /* состояние */
 12146	#define   STATUS_BSY            0x80    /* контроллер занят */
 12147	#define   STATUS_RDY            0x40    /* диск готов */
 12148	#define   STATUS_WF             0x20    /* ошибка при записи */
 12149	#define   STATUS_SC             0x10    /* поиск завершен (устар.) */
 12150	#define   STATUS_DRQ            0x08    /* запрос на передачу данных */
 12151	#define   STATUS_CRD            0x04    /* данные скорректированы */
 12152	#define   STATUS_IDX            0x02    /* индексный импульс */
 12153	#define   STATUS_ERR            0x01    /* ошибка */
 12154	#define   STATUS_ADMBSY        0x100    /* административная занятость (программная) */
 12155	#define REG_ERROR           1   /* код ошибки */
 12156	#define   ERROR_BB              0x80    /* поврежденный блок */
 12157	#define   ERROR_ECC             0x40    /* поврежденные ecc-байты */
 12158	#define   ERROR_ID              0x10    /* id не найден */
 12159	#define   ERROR_AC              0x04    /* команда отменена */
 12160	#define   ERROR_TK              0x02    /* отслеживание нулевой ошибки */
 12161	#define   ERROR_DM              0x01    /* пометка адреса данных отсутствует */
 12162	
 12163	/* Регистры только для записи */
 12164	#define REG_COMMAND         7   /* команда */
 12165	#define   CMD_IDLE              0x00    /* для w_command:  диск простаивает */
 12166	#define   CMD_RECALIBRATE       0x10    /* повторная калибровка диска */
 12167	#define   CMD_READ              0x20    /* чтение данных */
 12168	#define   CMD_READ_EXT          0x24    /* чтение данных (адресация LBA48) */
 12169	#define   CMD_WRITE             0x30    /* запись данных */
 12170	#define   CMD_WRITE_EXT         0x34    /* запись данных (адресация LBA48) */
 12171	#define   CMD_READVERIFY        0x40    /* проверка чтения */
 12172	#define   CMD_FORMAT            0x50    /* форматирование дорожки */
 12173	#define   CMD_SEEK              0x70    /* поиск цилиндра */
 12174	#define   CMD_DIAG              0x90    /* диагностика устройства */
 12175	#define   CMD_SPECIFY           0x91    /* задание параметров */
 12176	#define   ATA_IDENTIFY          0xEC    /* идентификация диска */
 12177	/* #define REG_CTL              0x206   */ /* управляющий регистр */
 12178	#define REG_CTL         0       /* управляющий регистр */
 12179	#define   CTL_NORETRY           0x80    /* запрещение повторной попытки доступа */
 12180	#define   CTL_NOECC             0x40    /* запрещение повторной коррекции ошибок */
 12181	#define   CTL_EIGHTHEADS        0x08    /* больше 8 головок */
 12182	#define   CTL_RESET             0x04    /* сброс контроллера */
 12183	#define   CTL_INTDISABLE        0x02    /* запрещение прерываний */
 12184	
 12185	#define REG_STATUS          7   /* состояние  */
 12186	#define   STATUS_BSY            0x80    /* контроллер занят */
 12187	#define   STATUS_DRDY           0x40    /* диск готов */
 12188	#define   STATUS_DMADF          0x20    /* dma готов/ошибка диска */
 12189	#define   STATUS_SRVCDSC        0x10    /* служба или dsc */
 12190	#define   STATUS_DRQ            0x08    /* запрос на передачу данных */
 12191	#define   STATUS_CORR           0x04    /* произошла корректируемая ошибка */
 12192	#define   STATUS_CHECK          0x01    /* ошибка проверки */
 12193	
 12194	/* Линии обслуживания прерываний. */
 12195	#define NO_IRQ           0      /* нет установленных IRQ */
 12196	
 12197	#define ATAPI_PACKETSIZE        12
 12198	#define SENSE_PACKETSIZE        18
 12199	
 12200	/* общий блок команды */
 12201	struct command {
 12202	  u8_t  precomp;        /* REG_PRECOMP и т. д. */
 12203	  u8_t  count;
 12204	  u8_t  sector;
 12205	  u8_t  cyl_lo;
 12206	  u8_t  cyl_hi;
 12207	  u8_t  ldh;
 12208	  u8_t  command;
 12209	};
 12210	
 12211	/* коды ошибок */
 12212	#define ERR              (-1)   /* общая ошибка */
 12213	#define ERR_BAD_SECTOR   (-2)   /* обнаружен блок, помеченный как неисправный */
 12214	
 12215	/* Некоторые контроллеры не генерируют прерываний, часы "разбудят" нас. */
 12216	#define WAKEUP          (32*HZ) /* диск может простаивать не более 31 с.*/
 12217	
 12218	/* Разное. */
 12219	#define MAX_DRIVES         8
 12220	#define COMPAT_DRIVES      4
 12221	#define MAX_SECS         256    /* число секторов, которое может передавать контроллер */
 12222	#define MAX_ERRORS         4    /* число повторных попыток чтения/записи */
 12223	#define NR_MINORS       (MAX_DRIVES * DEV_PER_DRIVE)
 12224	#define SUB_PER_DRIVE   (NR_PARTITIONS * NR_PARTITIONS)
 12225	#define NR_SUBDEVS      (MAX_DRIVES * SUB_PER_DRIVE)
 12226	#define DELAY_USECS     1000    /* таймаут контроллера в микросекундах */
 12227	#define DELAY_TICKS        1    /* таймаут контроллера в тактах часов  */
 12228	#define DEF_TIMEOUT_TICKS       300     /* таймаут контроллера в тактах часов */
 12229	#define RECOVERY_USECS 500000   /* время восстановления контроллера в микросекундах */
 12230	#define RECOVERY_TICKS    30    /* время восстановления контроллера в тактах часов */
 12231	#define INITIALIZED     0x01    /* драйвер инициализирован */
 12232	#define DEAF            0x02    /* контроллер необходимо сбросить */
 12233	#define SMART           0x04    /* диск поддерживает команды ATA */
 12234	#define ATAPI              0    /* не беспокоиться об ATAPI */
 12235	#define IDENTIFIED      0x10    /* успешное завершение w_identify */
 12236	#define IGNORING        0x20    /* однократное неудачное завершение w_identify */
 12237	
 12238	/* Таймауты и максимальные количества попыток. */
 12239	int timeout_ticks = DEF_TIMEOUT_TICKS, max_errors = MAX_ERRORS;
 12240	int wakeup_ticks = WAKEUP;
 12241	long w_standard_timeouts = 0, w_pci_debug = 0, w_instance = 0,
 12242	 w_lba48 = 0, atapi_debug = 0;
 12243	
 12244	int w_testing = 0, w_silent = 0;
 12245	
 12246	int w_next_drive = 0;
 12247	
 12248	/* Переменные. */
 12249	
 12250	/* сначала контроллером индексируется wini , а затем диски (0-3).
 12251	 * контроллер 0 - всегда "совместимый" ide-контроллер, находящийся в фиксированном
 12252	 * местоположении независимо от наличия.
 12253	 */
 12254	PRIVATE struct wini {           /* главная структура диска, одна запись на диск */
 12255	  unsigned state;               /* состояние диска: не отвечает, инициализирован, отключен */
 12256	  unsigned w_status;            /* регистр состояния устройства */
 12257	  unsigned base_cmd;            /* базовый регистр команд*/
 12258	  unsigned base_ctl;            /* базовый регистр управления */
 12259	  unsigned irq;                 /* линия запросов прерываний */
 12260	  unsigned irq_mask;            /* 1 << irq */
 12261	  unsigned irq_need_ack;        /* необходимо подтверждение irq */
 12262	  int irq_hook_id;              /* идентификатор обработчика прерывания в ядре */
 12263	  int lba48;                    /* есть поддержка lba48 */
 12264	  unsigned lcylinders;          /* логический номер цилиндров (BIOS) */
 12265	  unsigned lheads;              /* логический номер головок */
 12266	  unsigned lsectors;            /* логический номер секторов дорожки */
 12267	  unsigned pcylinders;          /* физический номер цилиндров (преобразован) */
 12268	  unsigned pheads;              /* физический номер дорожек */
 12269	  unsigned psectors;            /* физический номер секторов на дорожку */
 12270	  unsigned ldhpref;             /* четыре первых байта регистра LDH */
 12271	  unsigned precomp;             /* предкомпенсация при записи цилиндр / 4 */
 12272	  unsigned max_count;           /* максимальное число запросов к этому диску */
 12273	  unsigned open_ct;             /* внутренний счетчик */
 12274	  struct device part[DEV_PER_DRIVE];    /* диски и разделы */
 12275	  struct device subpart[SUB_PER_DRIVE]; /* подразделы */
 12276	} wini[MAX_DRIVES], *w_wn;
 12277	
 12278	PRIVATE int w_device = -1;
 12279	PRIVATE int w_controller = -1;
 12280	PRIVATE int w_major = -1;
 12281	PRIVATE char w_id_string[40];
 12282	
 12283	PRIVATE int win_tasknr;                 /* номер задания */
 12284	PRIVATE int w_command;                  /* текущая исполняемая команда */
 12285	PRIVATE u8_t w_byteval;                 /* используется для SYS_IRQCTL */
 12286	PRIVATE int w_drive;                    /* выбранный диск */
 12287	PRIVATE int w_controller;               /* выбранный контроллер */
 12288	PRIVATE struct device *w_dv;            /* базовый адрес и размер устройства */
 12289	
 12290	FORWARD _PROTOTYPE( void init_params, (void)                            );
 12291	FORWARD _PROTOTYPE( void init_drive, (struct wini *, int, int, int, int, int, int));
 12292	FORWARD _PROTOTYPE( void init_params_pci, (int)                         );
 12293	FORWARD _PROTOTYPE( int w_do_open, (struct driver *dp, message *m_ptr)  );
 12294	FORWARD _PROTOTYPE( struct device *w_prepare, (int dev)                 );
 12295	FORWARD _PROTOTYPE( int w_identify, (void)                              );
 12296	FORWARD _PROTOTYPE( char *w_name, (void)                                );
 12297	FORWARD _PROTOTYPE( int w_specify, (void)                               );
 12298	FORWARD _PROTOTYPE( int w_io_test, (void)                               );
 12299	FORWARD _PROTOTYPE( int w_transfer, (int proc_nr, int opcode, off_t position,
 12300	                                        iovec_t *iov, unsigned nr_req)  );
 12301	FORWARD _PROTOTYPE( int com_out, (struct command *cmd)                  );
 12302	FORWARD _PROTOTYPE( void w_need_reset, (void)                           );
 12303	FORWARD _PROTOTYPE( void ack_irqs, (unsigned int)                       );
 12304	FORWARD _PROTOTYPE( int w_do_close, (struct driver *dp, message *m_ptr) );
 12305	FORWARD _PROTOTYPE( int w_other, (struct driver *dp, message *m_ptr)    );
 12306	FORWARD _PROTOTYPE( int w_hw_int, (struct driver *dp, message *m_ptr)   );
 12307	FORWARD _PROTOTYPE( int com_simple, (struct command *cmd)               );
 12308	FORWARD _PROTOTYPE( void w_timeout, (void)                              );
 12309	FORWARD _PROTOTYPE( int w_reset, (void)                                 );
 12310	FORWARD _PROTOTYPE( void w_intr_wait, (void)                            );
 12311	FORWARD _PROTOTYPE( int at_intr_wait, (void)                            );
 12312	FORWARD _PROTOTYPE( int w_waitfor, (int mask, int value)                );
 12313	FORWARD _PROTOTYPE( void w_geometry, (struct partition *entry)          );
 12314	
 12315	/* Точки входа в этот драйвер. */
 12316	PRIVATE struct driver w_dtab = {
 12317	  w_name,               /* имя текущего устройства */
 12318	  w_do_open,            /* запрос на открытие или монтирование, инициализация устройства */
 12319	  w_do_close,           /* закрытие устройства */
 12320	  do_diocntl,           /* получение или задание геометрии раздела */
 12321	  w_prepare,            /* подготовка к вводу-выводу на заданном вспомогательном устройстве */
 12322	  w_transfer,           /* выполнение ввода-вывода */
 12323	  nop_cleanup,          /* нечего очищать */
 12324	  w_geometry,           /* определение геометрии диска */
 12325	  nop_signal,           /* очистка при завершении не требуется */
 12326	  nop_alarm,            /* игнорировать оставшиеся оповещения */
 12327	  nop_cancel,           /* игнорировать CANCEL */
 12328	  nop_select,           /* игнорировать select */
 12329	  w_other,              /* ловушка для нераспознанных команд и ioctl */
 12330	  w_hw_int              /* оставшиеся аппаратные прерывания */
 12331	};
 12332	
 12333	/*===========================================================================*
 12334	 *                              at_winchester_task                           *
 12335	 *===========================================================================*/
 12336	PUBLIC int main()
 12337	{
 12338	/* Задание специальных параметров диска с последующим вызовом главного цикла. */
 12339	  init_params();
 12340	  driver_task(&w_dtab);
 12341	  return(OK);
 12342	}
	
 12344	/*===========================================================================*
 12345	 *                              init_params                                  *
 12346	 *===========================================================================*/
 12347	PRIVATE void init_params()
 12348	{
 12349	/* Эта процедура вызывается для инициализации параметров диска при его запуске. */
 12350	
 12351	  u16_t parv[2];
 12352	  unsigned int vector, size;
 12353	  int drive, nr_drives;
 12354	  struct wini *wn;
 12355	  u8_t params[16];
 12356	  int s;
 12357	
 12358	  /* Переменные загрузки. */
 12359	  env_parse("ata_std_timeout", "d", 0, &w_standard_timeouts, 0, 1);
 12360	  env_parse("ata_pci_debug", "d", 0, &w_pci_debug, 0, 1);
 12361	  env_parse("ata_instance", "d", 0, &w_instance, 0, 8);
 12362	  env_parse("ata_lba48", "d", 0, &w_lba48, 0, 1);
 12363	  env_parse("atapi_debug", "d", 0, &atapi_debug, 0, 1);
 12364	
 12365	  if (w_instance == 0) {
 12366	          /* Получение числа дисков из области данных BIOS */
 12367	          if ((s=sys_vircopy(SELF, BIOS_SEG, NR_HD_DRIVES_ADDR, 
 12368	                        SELF, D, (vir_bytes) params, NR_HD_DRIVES_SIZE)) != OK)
 12369	                panic(w_name(), "Couldn't read BIOS", s);
 12370	          if ((nr_drives = params[0]) > 2) nr_drives = 2;
 12371	
 12372	          for (drive = 0, wn = wini; drive < COMPAT_DRIVES; drive++, wn++) {
 12373	                if (drive < nr_drives) {
 12374	                    /* Копирование вектора параметров BIOS */
 12375	                    vector = (drive == 0) ? BIOS_HD0_PARAMS_ADDR: BIOS_HD1_PARAMS_ADDR;
 12376	                    size = (drive == 0) ? BIOS_HD0_PARAMS_SIZE: BIOS_HD1_PARAMS_SIZE;
 12377	                    if ((s=sys_vircopy(SELF, BIOS_SEG, vector,
 12378	                                        SELF, D, (vir_bytes) parv, size)) != OK)
 12379	                                panic(w_name(), "Couldn't read BIOS", s);
 12380	        
 12381	                        /* Вычисление адреса параметров и их копирование */
 12382	                        if ((s=sys_vircopy(
 12383	                                SELF, BIOS_SEG, hclick_to_physb(parv[1]) + parv[0],
 12384	                                SELF, D, (phys_bytes) params, 16L))!=OK)
 12385	                            panic(w_name(),"Couldn't copy parameters", s);
 12386	        
 12387	                        /* Копирование параметров в структуры диска */
 12388	                        wn->lcylinders = bp_cylinders(params);
 12389	                        wn->lheads = bp_heads(params);
 12390	                        wn->lsectors = bp_sectors(params);
 12391	                        wn->precomp = bp_precomp(params) >> 2;
 12392	                }
 12393	
 12394	                /* Заполнение параметров, не связанных с BIOS. */
 12395	                init_drive(wn,
 12396	                        drive < 2 ? REG_CMD_BASE0 :  REG_CMD_BASE1,
 12397	                        drive < 2 ? REG_CTL_BASE0 :  REG_CTL_BASE1,
 12398	                        NO_IRQ, 0, 0, drive);
 12399	                w_next_drive++;
 12400	        }
 12401	  }
 12402	
 12403	  /* Поиск контроллеров на шине pci.
 12404	   *
 12405	   */
 12406	  if (w_instance == 0)
 12407	        init_params_pci(0);
 12408	  else
 12409	        init_params_pci(w_instance*2-1);
 12410	
 12411	}
	
 12413	#define ATA_IF_NOTCOMPAT1 (1L << 0)
 12414	#define ATA_IF_NOTCOMPAT2 (1L << 2)
 12415	
 12416	/*===========================================================================*
 12417	 *                              init_drive                                   *
 12418	 *===========================================================================*/
 12419	PRIVATE void init_drive(struct wini *w, int base_cmd, int base_ctl, int irq, int ack, int hook, int drive)
 12420	{
 12421	        w->state = 0;
 12422	        w->w_status = 0;
 12423	        w->base_cmd = base_cmd;
 12424	        w->base_ctl = base_ctl;
 12425	        w->irq = irq;
 12426	        w->irq_mask = 1 << irq;
 12427	        w->irq_need_ack = ack;
 12428	        w->irq_hook_id = hook;
 12429	        w->ldhpref = ldh_init(drive);
 12430	        w->max_count = MAX_SECS << SECTOR_SHIFT;
 12431	        w->lba48 = 0;
 12432	}
	
 12434	/*===========================================================================*
 12435	 *                              init_params_pci                              *
 12436	 *===========================================================================*/
 12437	PRIVATE void init_params_pci(int skip)
 12438	{
 12439	  int r, devind, drive;
 12440	  u16_t vid, did;
 12441	  pci_init();
 12442	  for(drive = w_next_drive; drive < MAX_DRIVES; drive++)
 12443	        wini[drive].state = IGNORING;
 12444	  for(r = pci_first_dev(&devind, &vid, &did);
 12445	        r != 0 && w_next_drive < MAX_DRIVES; r = pci_next_dev(&devind, &vid, &did)) {
 12446	        int interface, irq, irq_hook;
 12447	        /* Базовый класс должен быть 01h (накопитель большой емкости), подкласс должен
 12448	         * быть 01h (ATA).
 12449	         */
 12450	        if (pci_attr_r8(devind, PCI_BCR) != 0x01 ||
 12451	           pci_attr_r8(devind, PCI_SCR) != 0x01) {
 12452	           continue;
 12453	        }
 12454	        /* Найден контроллер.
 12455	         * Регистр интерфейса программирования даст дополнительную информацию.
 12456	         */
 12457	        interface = pci_attr_r8(devind, PCI_PIFR);
 12458	        irq = pci_attr_r8(devind, PCI_ILR);
 12459	
 12460	        /* Имеются ли несовместимые диски? */
 12461	        if (interface & (ATA_IF_NOTCOMPAT1 | ATA_IF_NOTCOMPAT2)) {
 12462	                int s;
 12463	                irq_hook = irq;
 12464	                if (skip > 0) {
 12465	                        if (w_pci_debug) printf("atapci skipping controller (remain %d)\n", skip);
 12466	                        skip--;
 12467	                        continue;
 12468	                }
 12469	                if ((s=sys_irqsetpolicy(irq, 0, &irq_hook)) != OK) {
 12470	                        printf("atapci:  couldn't set IRQ policy %d\n", irq);
 12471	                        continue;
 12472	                }
 12473	                if ((s=sys_irqenable(&irq_hook)) != OK) {
 12474	                        printf("atapci:  couldn't enable IRQ line %d\n", irq);
 12475	                        continue;
 12476	                }
 12477	        } else {
 12478	                /* Если нет, то это не тот контроллер ata-pci, который
 12479	                 * мы ищем.
 12480	                 */
 12481	                if (w_pci_debug) printf("atapci skipping compatability controller\n");
 12482	                continue;
 12483	        }
 12484	
 12485	        /* Находится ли главный канал в несовместимом режиме? */
 12486	        if (interface & ATA_IF_NOTCOMPAT1) {
 12487	                u32_t base_cmd, base_ctl;
 12488	                base_cmd = pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
 12489	                base_ctl = pci_attr_r32(devind, PCI_BAR_2) & 0xffffffe0;
 12490	                if (base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) {
 12491	                        init_drive(&wini[w_next_drive],
 12492	                                base_cmd, base_ctl, irq, 1, irq_hook, 0);
 12493	                        init_drive(&wini[w_next_drive+1],
 12494	                                base_cmd, base_ctl, irq, 1, irq_hook, 1);
 12495	                        if (w_pci_debug)
 12496	                                printf("atapci %d:  0x%x 0x%x irq %d\n", devind, base_cmd, base_ctl, irq);
 12497	                } else printf("atapci:  ignored drives on primary channel, base %x\n", base_cmd);
 12498	        }
 12499	
 12500	        /* Находится ли вторичный канал в несовместимом режиме? */
 12501	        if (interface & ATA_IF_NOTCOMPAT2) {
 12502	                u32_t base_cmd, base_ctl;
 12503	                base_cmd = pci_attr_r32(devind, PCI_BAR_3) & 0xffffffe0;
 12504	                base_ctl = pci_attr_r32(devind, PCI_BAR_4) & 0xffffffe0;
 12505	                if (base_cmd != REG_CMD_BASE0 && base_cmd != REG_CMD_BASE1) {
 12506	                        init_drive(&wini[w_next_drive+2],
 12507	                                base_cmd, base_ctl, irq, 1, irq_hook, 2);
 12508	                        init_drive(&wini[w_next_drive+3],
 12509	                                base_cmd, base_ctl, irq, 1, irq_hook, 3);
 12510	                        if (w_pci_debug)
 12511	                                printf("atapci %d:  0x%x 0x%x irq %d\n", devind, base_cmd, base_ctl, irq);
 12512	                } else printf("atapci:  ignored drives on secondary channel, base %x\n", base_cmd);
 12513	        }
 12514	        w_next_drive += 4;
 12515	  }
 12516	}
	
 12518	/*===========================================================================*
 12519	 *                              w_do_open                                    *
 12520	 *===========================================================================*/
 12521	PRIVATE int w_do_open(dp, m_ptr)
 12522	struct driver *dp;
 12523	message *m_ptr;
 12524	{
 12525	/* Открытие устройства:  инициализация контроллера и чтение таблицы разделов. */
 12526	
 12527	  struct wini *wn;
 12528	
 12529	  if (w_prepare(m_ptr->DEVICE) == NIL_DEV) return(ENXIO);
 12530	
 12531	  wn = w_wn;
 12532	
 12533	  /* Если мы проверяли устройство и проверка закончилась неудачей, мы не будет проверять его снова. */
 12534	  if (wn->state & IGNORING) return ENXIO;
 12535	
 12536	  /* Если устройство не идентифицировано или перестало отвечать, идентифицируем его 
 12537	   * (еще раз).
 12538	   */
 12539	  if (!(wn->state & IDENTIFIED) || (wn->state & DEAF)) {
 12540	        /* Попытка идентификации устройства. */
 12541	        if (w_identify() != OK) {
 12542	                if (wn->state & DEAF) w_reset();
 12543	                wn->state = IGNORING;
 12544	                return(ENXIO);
 12545	        }
 12546	          /* Тестовое обращение, если устройство не является CD-дисководом (в
 12547	           * этом случае мы доверяем контроллеру, а неудачный исход теста может
 12548	           * быть обусловлен отсутствием диска в дисководе). Если тест завершается
 12549	           * неудачно, устройство игнорируется навсегда.
 12550	           */
 12551	          if (!(wn->state & ATAPI) && w_io_test() != OK) {
 12552	                wn->state |= IGNORING;
 12553	                return(ENXIO);
 12554	          }
 12555	  }
 12556	
 12557	   /* Устройства, отличные от ATAPI, не будут открываться с использованием RO_BIT. */
 12558	   if (!(wn->state & ATAPI) && (m_ptr->COUNT & RO_BIT)) return EACCES;
 12559	
 12560	  /* Разбиение диска на разделы, если он используется впервые или открывается после
 12561	   * закрытия.
 12562	   */
 12563	  if (wn->open_ct == 0) {
 12564	
 12565	        /* Разбиение диска. */
 12566	        memset(wn->part, sizeof(wn->part), 0);
 12567	        memset(wn->subpart, sizeof(wn->subpart), 0);
 12568	        partition(&w_dtab, w_drive * DEV_PER_DRIVE, P_PRIMARY, wn->state & ATAPI);
 12569	  }
 12570	  wn->open_ct++;
 12571	  return(OK);
 12572	}
	
 12574	/*===========================================================================*
 12575	 *                              w_prepare                                    *
 12576	 *===========================================================================*/
 12577	PRIVATE struct device *w_prepare(int device)
 12578	{
 12579	/* Подготовка к вводу-выводу с устройства и на устройство. */
 12580	struct wini *prev_wn;
 12581	prev_wn = w_wn;
 12582	  w_device = device;
 12583	
 12584	  if (device < NR_MINORS) {                     /* d0, d0p[0-3], d1, ... */
 12585	        w_drive = device / DEV_PER_DRIVE;       /* сохранение номера диска */
 12586	        w_wn = &wini[w_drive];
 12587	        w_dv = &w_wn->part[device % DEV_PER_DRIVE];
 12588	  } else
 12589	  if ((unsigned) (device -= MINOR_d0p0s0) < NR_SUBDEVS) {/*d[0-7]p[0-3]s[0-3]*/
 12590	        w_drive = device / SUB_PER_DRIVE;
 12591	        w_wn = &wini[w_drive];
 12592	        w_dv = &w_wn->subpart[device % SUB_PER_DRIVE];
 12593	  } else {
 12594	        w_device = -1;
 12595	        return(NIL_DEV);
 12596	  }
 12597	  return(w_dv);
 12598	}
	
 12600	/*===========================================================================*
 12601	 *                              w_identify                                   *
 12602	 *===========================================================================*/
 12603	PRIVATE int w_identify()
 12604	{
 12605	/* Определение, существует ли устройство, является ли оно устаревшим AT-диском, более новым
 12606	 * ATA-диском, сменным накопителем и т. д.
 12607	 */
 12608	
 12609	  struct wini *wn = w_wn;
 12610	  struct command cmd;
 12611	  int i, s;
 12612	  unsigned long size;
 12613	#define id_byte(n)      (&tmp_buf[2 * (n)])
 12614	#define id_word(n)      (((u16_t) id_byte(n)[0] <<  0) \
 12615	                        |((u16_t) id_byte(n)[1] <<  8))
 12616	#define id_longword(n)  (((u32_t) id_byte(n)[0] <<  0) \
 12617	                        |((u32_t) id_byte(n)[1] <<  8) \
 12618	                        |((u32_t) id_byte(n)[2] << 16) \
 12619	                        |((u32_t) id_byte(n)[3] << 24))
 12620	
 12621	  /* Попытка идентифицировать устройство. */
 12622	  cmd.ldh     = wn->ldhpref;
 12623	  cmd.command = ATA_IDENTIFY;
 12624	  if (com_simple(&cmd) == OK) {
 12625	        /* Это ATA-устройство. */
 12626	        wn->state |= SMART;
 12627	
 12628	        /* Информация об устройстве. */
 12629	        if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK)
 12630	                panic(w_name(),"Call to sys_insw() failed", s);
 12631	
 12632	        /* Почему в строках переставлены байты??? */
 12633	        for (i = 0; i < 40; i++) w_id_string[i] = id_byte(27)[i^1];
 12634	
 12635	        /* Предпочтительный режим преобразования CHS. */
 12636	        wn->pcylinders = id_word(1);
 12637	        wn->pheads = id_word(3);
 12638	        wn->psectors = id_word(6);
 12639	        size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
 12640	
 12641	        if ((id_byte(49)[1] & 0x02) && size > 512L*1024*2) {
 12642	                /* Диск поддерживает логическую адресацию блоков и достаточно велик, чтобы 
 12643	                 * не вызвать путаницу с ней.
 12644	                 */
 12645	                wn->ldhpref |= LDH_LBA;
 12646	                size = id_longword(60);
 12647	
 12648	                if (w_lba48 && ((id_word(83)) & (1L << 10))) {
 12649	                        /* Диск поддерживает LBA48 (и режим LBA48 включен). */
 12650	                        if (id_word(102) || id_word(103)) {
 12651	                                /* Если номера секторов не умещаются в 32 бита,
 12652	                                 * округлить. Теперь разрядность адресов равна 32.
 12653	                                 * Тем не менее, этого достаточно для того, чтобы 
 12654	                                 * поддерживать устройства емкостью до 2 Тбайт.
 12655	                                 */
 12656	                                size = ULONG_MAX;
 12657	                        } else {
 12658	                                /* Фактическое число секторов умещается в 32 бита. */
 12659	                                size = id_longword(100);
 12660	                        }
 12661	
 12662	                        wn->lba48 = 1;
 12663	                }
 12664	        }
 12665	
 12666	        if (wn->lcylinders == 0) {
 12667	                /* Параметры BIOS отсутствуют? Заполнить их. */
 12668	                wn->lcylinders = wn->pcylinders;
 12669	                wn->lheads = wn->pheads;
 12670	                wn->lsectors = wn->psectors;
 12671	                while (wn->lcylinders > 1024) {
 12672	                        wn->lheads *= 2;
 12673	                        wn->lcylinders /= 2;
 12674	                }
 12675	        }
 12676	  } else {
 12677	        /* Устройство отличается от ATA; преобразований и специальных функций нет. Не 
 12678	         * иметь дело с устройством, если оно не известно BIOS.
 12679	         */
 12680	        if (wn->lcylinders == 0) { return(ERR); }       /* нет параметров BIOS */
 12681	        wn->pcylinders = wn->lcylinders;
 12682	        wn->pheads = wn->lheads;
 12683	        wn->psectors = wn->lsectors;
 12684	        size = (u32_t) wn->pcylinders * wn->pheads * wn->psectors;
 12685	  }
 12686	
 12687	  /* Размер всего диска */
 12688	  wn->part[0].dv_size = mul64u(size, SECTOR_SIZE);
 12689	
 12690	  /* сброс/калибровка (где необходимо) */
 12691	  if (w_specify() != OK && w_specify() != OK) {
 12692	        return(ERR);
 12693	  }
 12694	
 12695	  if (wn->irq == NO_IRQ) {
 12696	          /* Все выглядит корректно; регистрация IRQ для того, чтобы избавиться от опросов. */
 12697	          wn->irq = w_drive < 2 ? AT_WINI_0_IRQ :  AT_WINI_1_IRQ;
 12698	          wn->irq_hook_id = wn->irq;    /* нужно вернуть идентификатор, если произошло прерывание */
 12699	          if ((s=sys_irqsetpolicy(wn->irq, IRQ_REENABLE, &wn->irq_hook_id)) != OK) 
 12700	                panic(w_name(), "couldn't set IRQ policy", s);
 12701	          if ((s=sys_irqenable(&wn->irq_hook_id)) != OK)
 12702	                panic(w_name(), "couldn't enable IRQ line", s);
 12703	  }
 12704	  wn->state |= IDENTIFIED;
 12705	  return(OK);
 12706	}
	
 12708	/*===========================================================================*
 12709	 *                              w_name                                       *
 12710	 *===========================================================================*/
 12711	PRIVATE char *w_name()
 12712	{
 12713	/* Возврат имени текущего устройства. */
 12714	  static char name[] = "AT-D0";
 12715	
 12716	  name[4] = '0' + w_drive;
 12717	  return name;
 12718	}
	
 12720	/*===========================================================================*
 12721	 *                              w_io_test                                    *
 12722	 *===========================================================================*/
 12723	PRIVATE int w_io_test(void)
 12724	{
 12725	        int r, save_dev;
 12726	        int save_timeout, save_errors, save_wakeup;
 12727	        iovec_t iov;
 12728	        static char buf[SECTOR_SIZE];
 12729	        iov.iov_addr = (vir_bytes) buf;
 12730	        iov.iov_size = sizeof(buf);
 12731	        save_dev = w_device;
 12732	
 12733	        /* Уменьшение таймаутов для этого тестового обращения. */
 12734	        save_timeout = timeout_ticks;
 12735	        save_errors = max_errors;
 12736	        save_wakeup = wakeup_ticks;
 12737	
 12738	        if (!w_standard_timeouts) {
 12739	                timeout_ticks = HZ * 4;
 12740	                wakeup_ticks = HZ * 6;
 12741	                max_errors = 3;
 12742	        }
 12743	
 12744	        w_testing = 1;
 12745	
 12746	        /* Попытка ввода-вывода с/на фактическое устройство (не каждый (под)раздел). */
 12747	        if (w_prepare(w_drive * DEV_PER_DRIVE) == NIL_DEV)
 12748	                panic(w_name(), "Couldn't switch devices", NO_NUM);
 12749	
 12750	        r = w_transfer(SELF, DEV_GATHER, 0, &iov, 1);
 12751	
 12752	        /* Обратное переключение. */
 12753	        if (w_prepare(save_dev) == NIL_DEV)
 12754	                panic(w_name(), "Couldn't switch back devices", NO_NUM);
 12755	
 12756	        /* Восстановление параметров. */
 12757	        timeout_ticks = save_timeout;
 12758	        max_errors = save_errors;
 12759	        wakeup_ticks = save_wakeup;
 12760	        w_testing = 0;
 12761	
 12762	        /* Проверка, если все сработало. */
 12763	        if (r != OK || iov.iov_size != 0) {
 12764	                return ERR;
 12765	        }
 12766	
 12767	        /* Все сработало. */
 12768	
 12769	        return OK;
 12770	}
	
 12772	/*===========================================================================*
 12773	 *                              w_specify                                    *
 12774	 *===========================================================================*/
 12775	PRIVATE int w_specify()
 12776	{
 12777	/* Процедура инициализации диска после загрузки или при сбросе. */
 12778	
 12779	  struct wini *wn = w_wn;
 12780	  struct command cmd;
 12781	
 12782	  if ((wn->state & DEAF) && w_reset() != OK) {
 12783	        return(ERR);
 12784	  }
 12785	
 12786	  if (!(wn->state & ATAPI)) {
 12787	        /* Задание параметров: предкомпенсация, число головок и секторов. */
 12788	        cmd.precomp = wn->precomp;
 12789	        cmd.count   = wn->psectors;
 12790	        cmd.ldh     = w_wn->ldhpref | (wn->pheads - 1);
 12791	        cmd.command = CMD_SPECIFY;              /* Задание нескольких параметров */
 12792	
 12793	        /* Вывод блока команд и проверка, принимает ли контроллер параметры. */
 12794	        if (com_simple(&cmd) != OK) return(ERR);
 12795	
 12796	        if (!(wn->state & SMART)) {
 12797	                /* Calibrate an old disk. */
 12798	                cmd.sector  = 0;
 12799	                cmd.cyl_lo  = 0;
 12800	                cmd.cyl_hi  = 0;
 12801	                cmd.ldh     = w_wn->ldhpref;
 12802	                cmd.command = CMD_RECALIBRATE;
 12803	
 12804	                if (com_simple(&cmd) != OK) return(ERR);
 12805	        }
 12806	  }
 12807	  wn->state |= INITIALIZED;
 12808	  return(OK);
 12809	}
	
 12811	/*===========================================================================*
 12812	 *                              do_transfer                                  *
 12813	 *===========================================================================*/
 12814	PRIVATE int do_transfer(struct wini *wn, unsigned int precomp, unsigned int count,
 12815	        unsigned int sector, unsigned int opcode)
 12816	{
 12817	        struct command cmd;
 12818	        unsigned secspcyl = wn->pheads * wn->psectors;
 12819	
 12820	        cmd.precomp = precomp;
 12821	        cmd.count   = count;
 12822	        cmd.command = opcode == DEV_SCATTER ? CMD_WRITE :  CMD_READ;
 12823	        /* 
 12824	        if (w_lba48 && wn->lba48) {
 12825	        } else  */
 12826	        if (wn->ldhpref & LDH_LBA) {
 12827	                cmd.sector  = (sector >>  0) & 0xFF;
 12828	                cmd.cyl_lo  = (sector >>  8) & 0xFF;
 12829	                cmd.cyl_hi  = (sector >> 16) & 0xFF;
 12830	                cmd.ldh     = wn->ldhpref | ((sector >> 24) & 0xF);
 12831	        } else {
 12832	                int cylinder, head, sec;
 12833	                cylinder = sector / secspcyl;
 12834	                head = (sector % secspcyl) / wn->psectors;
 12835	                sec = sector % wn->psectors;
 12836	                cmd.sector  = sec + 1;
 12837	                cmd.cyl_lo  = cylinder & BYTE;
 12838	                cmd.cyl_hi  = (cylinder >> 8) & BYTE;
 12839	                cmd.ldh     = wn->ldhpref | head;
 12840	        }
 12841	
 12842	        return com_out(&cmd);
 12843	}
	
 12845	/*===========================================================================*
 12846	 *                              w_transfer                                   *
 12847	 *===========================================================================*/
 12848	PRIVATE int w_transfer(proc_nr, opcode, position, iov, nr_req)
 12849	int proc_nr;                    /* процесс, совершающий запрос */
 12850	int opcode;                     /* DEV_GATHER или DEV_SCATTER */
 12851	off_t position;                 /* смещение на устройстве при чтении или записи */
 12852	iovec_t *iov;                   /* указатель на вектор чтения или записи */
 12853	unsigned nr_req;                /* длина вектора запросов */
 12854	{
 12855	  struct wini *wn = w_wn;
 12856	  iovec_t *iop, *iov_end = iov + nr_req;
 12857	  int r, s, errors;
 12858	  unsigned long block;
 12859	  unsigned long dv_size = cv64ul(w_dv->dv_size);
 12860	  unsigned cylinder, head, sector, nbytes;
 12861	
 12862	  /* Проверка адреса диска. */
 12863	  if ((position & SECTOR_MASK) != 0) return(EINVAL);
 12864	
 12865	  errors = 0;
 12866	
 12867	  while (nr_req > 0) {
 12868	        /* Сколько байтов передать? */
 12869	        nbytes = 0;
 12870	        for (iop = iov; iop < iov_end; iop++) nbytes += iop->iov_size;
 12871	        if ((nbytes & SECTOR_MASK) != 0) return(EINVAL);
 12872	
 12873	        /* Какой блок диска и на каком расстоянии от конца файла? */
 12874	        if (position >= dv_size) return(OK);            /* в конце файла */
 12875	        if (position + nbytes > dv_size) nbytes = dv_size - position;
 12876	        block = div64u(add64ul(w_dv->dv_base, position), SECTOR_SIZE);
 12877	
 12878	        if (nbytes >= wn->max_count) {
 12879	                /* Диск не может обрабатывать больше, чем max_count операций за раз. */
 12880	                nbytes = wn->max_count;
 12881	        }
 12882	
 12883	        /* Сначала проверка необходимости повторной инициализации. */
 12884	        if (!(wn->state & INITIALIZED) && w_specify() != OK) return(EIO);
 12885	
 12886	        /* Команда контроллеру передать nbytes байтов. */
 12887	        r = do_transfer(wn, wn->precomp, ((nbytes >> SECTOR_SHIFT) & BYTE),
 12888	                block, opcode);
 12889	
 12890	        while (r == OK && nbytes > 0) {
 12891	                /* Для каждого сектора дождаться прерывания и получить данные (при 
 12892	                 * чтении) или передать данные контроллеру и дождаться прерывания (при
 12893	                 * записи).
 12894	                 */
 12895	
 12896	                if (opcode == DEV_GATHER) {
 12897	                        /* Сначала прерывание, затем данные. */
 12898	                        if ((r = at_intr_wait()) != OK) {
 12899	                                /* Ошибка, послать данные в битоприемник. */
 12900	                                if (w_wn->w_status & STATUS_DRQ) {
 12901	        if ((s=sys_insw(wn->base_cmd + REG_DATA, SELF, tmp_buf, SECTOR_SIZE)) != OK)
 12902	                panic(w_name(),"Call to sys_insw() failed", s);
 12903	                                }
 12904	                                break;
 12905	                        }
 12906	                }
 12907	
 12908	                /* Ожидание запроса на передачу данных. */
 12909	                if (!w_waitfor(STATUS_DRQ, STATUS_DRQ)) { r = ERR; break; }
 12910	
 12911	                /* Копирование байтов из буфера и в буфер устройства. */
 12912	                if (opcode == DEV_GATHER) {
 12913	        if ((s=sys_insw(wn->base_cmd + REG_DATA, proc_nr, (void *) iov->iov_addr, SECTOR_SIZE)) != OK)
 12914	                panic(w_name(),"Call to sys_insw() failed", s);
 12915	                } else {
 12916	        if ((s=sys_outsw(wn->base_cmd + REG_DATA, proc_nr, (void *) iov->iov_addr, SECTOR_SIZE)) != OK)
 12917	                panic(w_name(),"Call to sys_insw() failed", s);
 12918	
 12919	                        /* Данные переданы, ожидание прерывания. */
 12920	                        if ((r = at_intr_wait()) != OK) break;
 12921	                }
 12922	
 12923	                /* Учет успешно переданных байтов. */
 12924	                nbytes -= SECTOR_SIZE;
 12925	                position += SECTOR_SIZE;
 12926	                iov->iov_addr += SECTOR_SIZE;
 12927	                if ((iov->iov_size -= SECTOR_SIZE) == 0) { iov++; nr_req--; }
 12928	        }
 12929	
 12930	        /* Есть ли ошибки? */
 12931	        if (r != OK) {
 12932	                /* Не предпринимать повторную попытку, если сектор неисправен или слишком много ошибок. */
 12933	                if (r == ERR_BAD_SECTOR || ++errors == max_errors) {
 12934	                        w_command = CMD_IDLE;
 12935	                        return(EIO);
 12936	                }
 12937	        }
 12938	  }
 12939	
 12940	  w_command = CMD_IDLE;
 12941	  return(OK);
 12942	}
	
 12944	/*===========================================================================*
 12945	 *                              com_out                                      *
 12946	 *===========================================================================*/
 12947	PRIVATE int com_out(cmd)
 12948	struct command *cmd;            /* блок команд */
 12949	{
 12950	/* Вывод блока команд на контроллер жесткого диска и возврат состояния */
 12951	
 12952	  struct wini *wn = w_wn;
 12953	  unsigned base_cmd = wn->base_cmd;
 12954	  unsigned base_ctl = wn->base_ctl;
 12955	  pvb_pair_t outbyte[7];                /* вектор для sys_voutb() */
 12956	  int s;                                /* состояние для sys_(v)outb() */
 12957	
 12958	  if (w_wn->state & IGNORING) return ERR;
 12959	
 12960	  if (!w_waitfor(STATUS_BSY, 0)) {
 12961	        printf("%s:  controller not ready\n", w_name());
 12962	        return(ERR);
 12963	  }
 12964	
 12965	  /* Выбор устройства. */
 12966	  if ((s=sys_outb(base_cmd + REG_LDH, cmd->ldh)) != OK)
 12967	        panic(w_name(),"Couldn't write register to select drive",s);
 12968	
 12969	  if (!w_waitfor(STATUS_BSY, 0)) {
 12970	        printf("%s:  com_out:  drive not ready\n", w_name());
 12971	        return(ERR);
 12972	  }
 12973	
 12974	  /* Планирование вызова, выводящего контроллер из ожидания. Это выполняется с помощью
 12975	   * синхронного оповещения. Если происходит таймаут, посылается сообщение SYN_ALARM 
 12976	   * от HARDWARE, чтобы функция w_intr_wait() могла вызвать функцию w_timeout() в случае, 
 12977	   * если контроллер не смог выполнить команду. Оставшиеся таймауты игнорируются главным 
 12978	   * циклом. 
 12979	   */
 12980	  sys_setalarm(wakeup_ticks, 0);
 12981	
 12982	  wn->w_status = STATUS_ADMBSY;
 12983	  w_command = cmd->command;
 12984	  pv_set(outbyte[0], base_ctl + REG_CTL, wn->pheads >= 8 ? CTL_EIGHTHEADS :  0);
 12985	  pv_set(outbyte[1], base_cmd + REG_PRECOMP, cmd->precomp);
 12986	  pv_set(outbyte[2], base_cmd + REG_COUNT, cmd->count);
 12987	  pv_set(outbyte[3], base_cmd + REG_SECTOR, cmd->sector);
 12988	  pv_set(outbyte[4], base_cmd + REG_CYL_LO, cmd->cyl_lo);
 12989	  pv_set(outbyte[5], base_cmd + REG_CYL_HI, cmd->cyl_hi);
 12990	  pv_set(outbyte[6], base_cmd + REG_COMMAND, cmd->command);
 12991	  if ((s=sys_voutb(outbyte,7)) != OK)
 12992	        panic(w_name(),"Couldn't write registers with sys_voutb()",s);
 12993	  return(OK);
 12994	}
	
 12996	/*===========================================================================*
 12997	 *                              w_need_reset                                 *
 12998	 *===========================================================================*/
 12999	PRIVATE void w_need_reset()
 13000	{
 13001	/* Контроллер необходимо сбросить. */
 13002	  struct wini *wn;
 13003	  int dr = 0;
 13004	
 13005	  for (wn = wini; wn < &wini[MAX_DRIVES]; wn++, dr++) {
 13006	        if (wn->base_cmd == w_wn->base_cmd) {
 13007	                wn->state |= DEAF;
 13008	                wn->state &= ~INITIALIZED;
 13009	        }
 13010	  }
 13011	}
	
 13013	/*===========================================================================*
 13014	 *                              w_do_close                                   *
 13015	 *===========================================================================*/
 13016	PRIVATE int w_do_close(dp, m_ptr)
 13017	struct driver *dp;
 13018	message *m_ptr;
 13019	{
 13020	/* Закрытие устройства:  освободить устройство. */
 13021	  if (w_prepare(m_ptr->DEVICE) == NIL_DEV)
 13022	        return(ENXIO);
 13023	  w_wn->open_ct--;
 13024	  return(OK);
 13025	}
	
 13027	/*===========================================================================*
 13028	 *                              com_simple                                   *
 13029	 *===========================================================================*/
 13030	PRIVATE int com_simple(cmd)
 13031	struct command *cmd;            /* блок команд */
 13032	{
 13033	/* Простая команда контроллера, только прерывание без фазы вывода данных. */
 13034	  int r;
 13035	
 13036	  if (w_wn->state & IGNORING) return ERR;
 13037	
 13038	  if ((r = com_out(cmd)) == OK) r = at_intr_wait();
 13039	  w_command = CMD_IDLE;
 13040	  return(r);
 13041	}
	
 13043	/*===========================================================================*
 13044	 *                              w_timeout                                    *
 13045	 *===========================================================================*/
 13046	PRIVATE void w_timeout(void)
 13047	{
 13048	  struct wini *wn = w_wn;
 13049	
 13050	  switch (w_command) {
 13051	  case CMD_IDLE: 
 13052	        break;          /* замечательно */
 13053	  case CMD_READ: 
 13054	  case CMD_WRITE: 
 13055	        /* Невозможно, но не на стороне компьютера: контроллер не отвечает. */
 13056	
 13057	        /* Ограничение многосекторного вывода кажется подходящим */
 13058	        if (wn->max_count > 8 * SECTOR_SIZE) {
 13059	                wn->max_count = 8 * SECTOR_SIZE;
 13060	        } else {
 13061	                wn->max_count = SECTOR_SIZE;
 13062	        }
 13063	        /* дальше */
 13064	  default: 
 13065	        /* Какая-то другая команда. */
 13066	        if (w_testing)  wn->state |= IGNORING;  /* Игнорировать данный диск. */
 13067	        else if (!w_silent) printf("%s:  timeout on command %02x\n", w_name(), w_command);
 13068	        w_need_reset();
 13069	        wn->w_status = 0;
 13070	  }
 13071	}
	
 13073	/*===========================================================================*
 13074	 *                              w_reset                                      *
 13075	 *===========================================================================*/
 13076	PRIVATE int w_reset()
 13077	{
 13078	/* Сброс контроллера. Это делается после любого сбоя, например, после того, как контроллер
 13079	 * перестал отвечать.
 13080	 */
 13081	  int s;
 13082	  struct wini *wn = w_wn;
 13083	
 13084	  /* Не беспокоиться, если диск игнорируется. */
 13085	  if (w_wn->state & IGNORING) return ERR;
 13086	
 13087	  /* Ожидание любого внутреннего восстановления диска. */
 13088	  tickdelay(RECOVERY_TICKS);
 13089	
 13090	  /* Стробирование бита сброса */
 13091	  if ((s=sys_outb(wn->base_ctl + REG_CTL, CTL_RESET)) != OK)
 13092	        panic(w_name(),"Couldn't strobe reset bit",s);
 13093	  tickdelay(DELAY_TICKS);
 13094	  if ((s=sys_outb(wn->base_ctl + REG_CTL, 0)) != OK)
 13095	        panic(w_name(),"Couldn't strobe reset bit",s);
 13096	  tickdelay(DELAY_TICKS);
 13097	
 13098	  /* Ожидание готовности контроллера */
 13099	  if (!w_waitfor(STATUS_BSY, 0)) {
 13100	        printf("%s:  reset failed, drive busy\n", w_name());
 13101	        return(ERR);
 13102	  }
 13103	
 13104	  /* Теперь следует проверить регистр ошибок, однако некоторые диски работают с ним некорректно. */
 13105	
 13106	  for (wn = wini; wn < &wini[MAX_DRIVES]; wn++) {
 13107	        if (wn->base_cmd == w_wn->base_cmd) {
 13108	                wn->state &= ~DEAF;
 13109	                if (w_wn->irq_need_ack) {
 13110	                        /* Убедиться, что прерывание действительно разрешено. */
 13111	                        sys_irqenable(&w_wn->irq_hook_id);
 13112	                }
 13113	        }
 13114	  }
 13115	                
 13116	
 13117	  return(OK);
 13118	}
	
 13120	/*===========================================================================*
 13121	 *                              w_intr_wait                                  *
 13122	 *===========================================================================*/
 13123	PRIVATE void w_intr_wait()
 13124	{
 13125	/* Ожидание прерывания завершения задания. */
 13126	
 13127	  message m;
 13128	
 13129	  if (w_wn->irq != NO_IRQ) {
 13130	        /* Ожидание прерывания, задающего состояние "не занят" в переменной w_status. */
 13131	        while (w_wn->w_status & (STATUS_ADMBSY|STATUS_BSY)) {
 13132	                receive(ANY, &m);               /* ожидание сообщения HARD_INT */
 13133	                if (m.m_type == SYN_ALARM) {    /* проверка таймаута */
 13134	                    w_timeout();                /* за счет установки w_status */
 13135	                } else if (m.m_type == HARD_INT) {
 13136	                    sys_inb(w_wn->base_cmd + REG_STATUS, &w_wn->w_status);
 13137	                    ack_irqs(m.NOTIFY_ARG);
 13138	                } else {
 13139	                        printf("AT_WINI got unexpected message %d from %d\n",
 13140	                                m.m_type, m.m_source);
 13141	                }
 13142	        }
 13143	  } else {
 13144	        /* Прерывание еще не выделено; использовать опрос. */
 13145	        (void) w_waitfor(STATUS_BSY, 0);
 13146	  }
 13147	}
	
 13149	/*===========================================================================*
 13150	 *                              at_intr_wait                                 *
 13151	 *===========================================================================*/
 13152	PRIVATE int at_intr_wait()
 13153	{
 13154	/* Ожидание прерывания, проверка битов состояния и возврат ошибки/успеха. */
 13155	  int r;
 13156	  int s,inbval;         /* чтение значение с помощью sys_inb */ 
 13157	
 13158	  w_intr_wait();
 13159	  if ((w_wn->w_status & (STATUS_BSY | STATUS_WF | STATUS_ERR)) == 0) {
 13160	        r = OK;
 13161	  } else {
 13162	        if ((s=sys_inb(w_wn->base_cmd + REG_ERROR, &inbval)) != OK)
 13163	                panic(w_name(),"Couldn't read register",s);
 13164	        if ((w_wn->w_status & STATUS_ERR) && (inbval & ERROR_BB)) {
 13165	                r = ERR_BAD_SECTOR;     /* сектор помечен как дефектный, повторы не помогут */
 13166	        } else {
 13167	                r = ERR;                /* любая другая ошибка */
 13168	        }
 13169	  }
 13170	  w_wn->w_status |= STATUS_ADMBSY;      /* предполагаем, что контроллер до сих пор занят */
 13171	  return(r);
 13172	}
	
 13174	/*===========================================================================*
 13175	 *                              w_waitfor                                    *
 13176	 *===========================================================================*/
 13177	PRIVATE int w_waitfor(mask, value)
 13178	int mask;                       /* маска состояния */
 13179	int value;                      /* требуемое состояние */
 13180	{
 13181	/* Ожидание до тех пор, пока контроллер не окажется в нужном состоянии. При таймауте
 13182	 * возвращается 0. Флаг таймаута устанавливается путем оповещения. Значение TIMEOUT задается
 13183	 * в микросекундам, однако нам необходимы такты часов. Отключать оповещение не требуется,
 13184	 * поскольку флаг статический, а оставшийся таймаут не способен нанести вред.
 13185	 */
 13186	  clock_t t0, t1;
 13187	  int s;
 13188	  getuptime(&t0);
 13189	  do {
 13190	        if ((s=sys_inb(w_wn->base_cmd + REG_STATUS, &w_wn->w_status)) != OK)
 13191	                panic(w_name(),"Couldn't read register",s);
 13192	        if ((w_wn->w_status & mask) == value) {
 13193	                return 1;
 13194	        }
 13195	  } while ((s=getuptime(&t1)) == OK && (t1-t0) < timeout_ticks );
 13196	  if (OK != s) printf("AT_WINI:  warning, get_uptime failed:  %d\n",s);
 13197	
 13198	  w_need_reset();                       /* контроллер перестал отвечать */
 13199	  return(0);
 13200	}
	
 13202	/*===========================================================================*
 13203	 *                              w_geometry                                   *
 13204	 *===========================================================================*/
 13205	PRIVATE void w_geometry(entry)
 13206	struct partition *entry;
 13207	{
 13208	  struct wini *wn = w_wn;
 13209	
 13210	  if (wn->state & ATAPI) {              /* Задание нескольких параметров. */
 13211	        entry->cylinders = div64u(wn->part[0].dv_size, SECTOR_SIZE) / (64*32);
 13212	        entry->heads = 64;
 13213	        entry->sectors = 32;
 13214	  } else {                              /* Возврат логической геометрии. */
 13215	        entry->cylinders = wn->lcylinders;
 13216	        entry->heads = wn->lheads;
 13217	        entry->sectors = wn->lsectors;
 13218	  }
 13219	}
	
 13221	/*===========================================================================*
 13222	 *                              w_other                                      *
 13223	 *===========================================================================*/
 13224	PRIVATE int w_other(dr, m)
 13225	struct driver *dr;
 13226	message *m;
 13227	{
 13228	        int r, timeout, prev;
 13229	
 13230	        if (m->m_type != DEV_IOCTL ) {
 13231	                return EINVAL;
 13232	        }
 13233	
 13234	        if (m->REQUEST == DIOCTIMEOUT) {
 13235	                if ((r=sys_datacopy(m->PROC_NR, (vir_bytes)m->ADDRESS,
 13236	                        SELF, (vir_bytes)&timeout, sizeof(timeout))) != OK)
 13237	                        return r;
 13238	        
 13239	                if (timeout == 0) {
 13240	                        /* Восстановление значений по умолчанию. */
 13241	                        timeout_ticks = DEF_TIMEOUT_TICKS;
 13242	                        max_errors = MAX_ERRORS;
 13243	                        wakeup_ticks = WAKEUP;
 13244	                        w_silent = 0;
 13245	                } else if (timeout < 0) {
 13246	                        return EINVAL;
 13247	                } else  {
 13248	                        prev = wakeup_ticks;
 13249	        
 13250	                        if (!w_standard_timeouts) {
 13251	                                /* Установка (меньшего) таймаута, меньшей толерантности
 13252	                                 * к ошибкам и "тихого" режима.
 13253	                                 */
 13254	                                wakeup_ticks = timeout;
 13255	                                max_errors = 3;
 13256	                                w_silent = 1;
 13257	        
 13258	                                if (timeout_ticks > timeout)
 13259	                                        timeout_ticks = timeout;
 13260	                        }
 13261	        
 13262	                        if ((r=sys_datacopy(SELF, (vir_bytes)&prev, 
 13263	                                m->PROC_NR, (vir_bytes)m->ADDRESS, sizeof(prev))) != OK)
 13264	                                return r;
 13265	                }
 13266	        
 13267	                return OK;
 13268	        } else  if (m->REQUEST == DIOCOPENCT) {
 13269	                int count;
 13270	                if (w_prepare(m->DEVICE) == NIL_DEV) return ENXIO;
 13271	                count = w_wn->open_ct;
 13272	                if ((r=sys_datacopy(SELF, (vir_bytes)&count, 
 13273	                        m->PROC_NR, (vir_bytes)m->ADDRESS, sizeof(count))) != OK)
 13274	                        return r;
 13275	                return OK;
 13276	        }
 13277	        return EINVAL;
 13278	}
	
 13280	/*===========================================================================*
 13281	 *                              w_hw_int                                     *
 13282	 *===========================================================================*/
 13283	PRIVATE int w_hw_int(dr, m)
 13284	struct driver *dr;
 13285	message *m;
 13286	{
 13287	  /* Получено оставшееся прерывание (-я); его (их) подтверждение. */
 13288	  ack_irqs(m->NOTIFY_ARG);
 13289	
 13290	  return OK;
 13291	}
	
	
 13294	/*===========================================================================*
 13295	 *                              ack_irqs                                     *
 13296	 *===========================================================================*/
 13297	PRIVATE void ack_irqs(unsigned int irqs)
 13298	{
 13299	  unsigned int drive;
 13300	  for (drive = 0; drive < MAX_DRIVES && irqs; drive++) {
 13301	        if (!(wini[drive].state & IGNORING) && wini[drive].irq_need_ack &&
 13302	                (wini[drive].irq_mask & irqs)) {
 13303	                if (sys_inb((wini[drive].base_cmd + REG_STATUS), &wini[drive].w_status) != OK)
 13304	                        printf("couldn't ack irq on drive %d\n", drive);
 13305	                if (sys_irqenable(&wini[drive].irq_hook_id) != OK)
 13306	                        printf("couldn't re-enable drive %d\n", drive);
 13307	                irqs &= ~wini[drive].irq_mask;
 13308	        }
 13309	  }
 13310	}
	
	
 13313	#define STSTR(a) if (status & STATUS_ ## a) { strcat(str, #a); strcat(str, " "); }
 13314	#define ERRSTR(a) if (e & ERROR_ ## a) { strcat(str, #a); strcat(str, " "); }
 13315	char *strstatus(int status)
 13316	{
 13317	        static char str[200];
 13318	        str[0] = '\0';
 13319	
 13320	        STSTR(BSY);
 13321	        STSTR(DRDY);
 13322	        STSTR(DMADF);
 13323	        STSTR(SRVCDSC);
 13324	        STSTR(DRQ);
 13325	        STSTR(CORR);
 13326	        STSTR(CHECK);
 13327	        return str;
 13328	}
	
 13330	char *strerr(int e)
 13331	{
 13332	        static char str[200];
 13333	        str[0] = '\0';
 13334	
 13335	        ERRSTR(BB);
 13336	        ERRSTR(ECC);
 13337	        ERRSTR(ID);
 13338	        ERRSTR(AC);
 13339	        ERRSTR(TK);
 13340	        ERRSTR(DM);
 13341	
 13342	        return str;
 13343	}




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      drivers/tty/tty.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 13400	/*      tty.h - терминалы       */
 13401	
 13402	#include <timers.h>
 13403	
 13404	/* Первые вспомогательные номера для различных классов терминальных устройств. */
 13405	#define CONS_MINOR         0
 13406	#define LOG_MINOR         15
 13407	#define RS232_MINOR       16
 13408	#define TTYPX_MINOR      128
 13409	#define PTYPX_MINOR      192
 13410	
 13411	#define LINEWRAP           1    /* console.c - перенос строки в столбце 80*/
 13412	
 13413	#define TTY_IN_BYTES     256    /* размер входной очереди терминала */
 13414	#define TAB_SIZE           8    /* длина табуляции */
 13415	#define TAB_MASK           7    /* маска для вычисления положения курсора после нажатия табуляции */
 13416	
 13417	#define ESC             '\33'   /* escape */
 13418	
 13419	#define O_NOCTTY       00400    /* из <fcntl.h> */
 13420	#define O_NONBLOCK     04000
 13421	
 13422	struct tty;
 13423	typedef _PROTOTYPE( int (*devfun_t), (struct tty *tp, int try_only) );
 13424	typedef _PROTOTYPE( void (*devfunarg_t), (struct tty *tp, int c) );
 13425	
 13426	typedef struct tty {
 13427	  int tty_events;               /* устанавливается, когда терминал должен проверить эту строку */
 13428	  int tty_index;                /* индекс таблицы терминалов */
 13429	  int tty_minor;                /* вспомогательный номер устройства */
 13430	
 13431	  /* Входная очередь.  Введенные символы хранятся в ней, пока программа не считывает их. */
 13432	  u16_t *tty_inhead;            /* указатель на память для следующего символа */
 13433	  u16_t *tty_intail;            /* указатель на следующий символ, который должен быть передан программе */
 13434	  int tty_incount;              /* число символов во входной очереди */
 13435	  int tty_eotct;                /* число"разрывов строки" во входной очереди */
 13436	  devfun_t tty_devread;         /* подпрограмма, считывающая из буферов нижнего уровня */
 13437	  devfun_t tty_icancel;         /* полная отмена ввода из устройства */
 13438	  int tty_min;                  /* минимальное требуемое количество символов во входной очереди */
 13439	  timer_t tty_tmr;              /* таймер этого терминала */
 13440	
 13441	  /* Раздел вывода. */
 13442	  devfun_t tty_devwrite;        /* подпрограмма, инициирующая фактический вывод устройства */
 13443	  devfunarg_t tty_echo;         /* подпрограмма, выполняющая эхо-вывод вводимых символов */
 13444	  devfun_t tty_ocancel;         /* отмена всего текущего вывода устройства */
 13445	  devfun_t tty_break;           /* передача устройством символа конца строки */
 13446	
 13447	  /* Параметры и состояние терминала. */
 13448	  int tty_position;             /* текущая позиция на экране для эхо-вывода */
 13449	  char tty_reprint;             /* 1 при сбое эхо-вывода, иначе 0 */
 13450	  char tty_escaped;             /* 1 при обнаружении LNEXT (^V), иначе 0 */
 13451	  char tty_inhibited;           /* 1 при обнаружении STOP (^S), иначе 0 (остановка ввода) */
 13452	  char tty_pgrp;                /* номер записи контролирующего процесса */
 13453	  char tty_openct;              /* счетчик числа открытий этого терминала */
 13454	
 13455	  /* Информация о незавершенных запросах ввода-вывода хранится здесь. */
 13456	  char tty_inrepcode;           /* код ответа - TASK_REPLY или REVIVE */
 13457	  char tty_inrevived;           /* устанавливается в 1 при ожидании возобновления */
 13458	  char tty_incaller;            /* процесс, выполнивший вызов (обычно файловая система) */
 13459	  char tty_inproc;              /* процесс, желающий считать ввод из терминала */
 13460	  vir_bytes tty_in_vir;         /* виртуальный адрес, по которому помещаются данные */
 13461	  int tty_inleft;               /* сколько символов осталось */
 13462	  int tty_incum;                /* число введенных символов */
 13463	  char tty_outrepcode;          /* код ответа, TASK_REPLY или REVIVE */
 13464	  char tty_outrevived;          /* устанавливается в 1 при ожидании возобновления */
 13465	  char tty_outcaller;           /* процесс, выполнивший вызов (обычно файловая система) */
 13466	  char tty_outproc;             /* процесс, желающий записать в терминал */
 13467	  vir_bytes tty_out_vir;        /* виртуальный адрес, по которому считываются данные */
 13468	  int tty_outleft;              /* число символов, оставшихся для вывода */
 13469	  int tty_outcum;               /* число выведенных символов */
 13470	  char tty_iocaller;            /* процесс, выполнивший вызов (обычно файловая система) */
 13471	  char tty_ioproc;              /* процесс, желающий выполнить ioctl */
 13472	  int tty_ioreq;                /* код запроса ioctl */
 13473	  vir_bytes tty_iovir;          /* виртуальный адрес буфера ioctl */
 13474	
 13475	  /* выбор данных */
 13476	  int tty_select_ops;           /* интересующие операции */
 13477	  int tty_select_proc;          /* процесс, желающий получить уведомление */
 13478	
 13479	  /* Разное. */
 13480	  devfun_t tty_ioctl;           /* выбор скорости линии и т. д. На уровне устройства */
 13481	  devfun_t tty_close;           /* информировать устройство о том, что терминал закрыт */
 13482	  void *tty_priv;               /* указатель на закрытые данные устройства */
 13483	  struct termios tty_termios;   /* атрибуты терминала */
 13484	  struct winsize tty_winsize;   /* размер окна (число строк и число столбцов) */
 13485	
 13486	  u16_t tty_inbuf[TTY_IN_BYTES];/* входной буфер терминала */
 13487	
 13488	} tty_t;
 13489	
 13490	/* Память, выделенная в tty.c и внешняя здесь. */
 13491	extern tty_t tty_table[NR_CONS+NR_RS_LINES+NR_PTYS];
 13492	extern int ccurrent;            /* текущая видимая консоль */
 13493	extern int irq_hook_id;         /* идентификатор обработчика прерывания клавиатуры */
 13494	
 13495	extern unsigned long kbd_irq_set;
 13496	extern unsigned long rs_irq_set;
 13497	
 13498	/* Значения полей. */
 13499	#define NOT_ESCAPED        0    /* предыдущий символ отличен от LNEXT (^V) */
 13500	#define ESCAPED            1    /* предыдущий символ является LNEXT (^V) */
 13501	#define RUNNING            0    /* символ STOP (^S) не был введен */
 13502	#define STOPPED            1    /* символ STOP (^S) был введен */
 13503	
 13504	/* Поля и флаги для символов во входной очереди. */
 13505	#define IN_CHAR       0x00FF    /* младшие 8 бит – сам символ */
 13506	#define IN_LEN        0x0F00    /* длина символа, если был его эхо-вывод */
 13507	#define IN_LSHIFT          8    /* length = (c & IN_LEN) >> IN_LSHIFT */
 13508	#define IN_EOT        0x1000    /* символ конца строки (^D, LF) */
 13509	#define IN_EOF        0x2000    /* символ конца файла EOF (^D), не возвращать пользователю */
 13510	#define IN_ESC        0x4000    /* отменен символом LNEXT (^V), не нужно интерпретировать */
 13511	
 13512	/* Таймауты. */
 13513	#define force_timeout() ((void) (0))
 13514	
 13515	/* Память, выделенная в tty.c и внешняя здесь. */
 13516	extern timer_t *tty_timers;             /* очередь таймеров терминала */
 13517	extern clock_t tty_next_timeout;        /* следующий таймаут терминала */
 13518	
 13519	/* Число элементов и граница буфера. */
 13520	#define buflen(buf)     (sizeof(buf) / sizeof((buf)[0]))
 13521	#define bufend(buf)     ((buf) + buflen(buf))
 13522	
 13523	/* Память, выделенная в tty.c и внешняя здесь. */
 13524	extern struct machine machine;  /* информация о компьютере (pc_at, ega) */
 13525	
 13526	/* Прототипы функций для драйвера терминала. */
 13527	/* tty.c */
 13528	_PROTOTYPE( void handle_events, (struct tty *tp)                        );
 13529	_PROTOTYPE( void sigchar, (struct tty *tp, int sig)                     );
 13530	_PROTOTYPE( void tty_task, (void)                                       );
 13531	_PROTOTYPE( int in_process, (struct tty *tp, char *buf, int count)      );
 13532	_PROTOTYPE( void out_process, (struct tty *tp, char *bstart, char *bpos,
 13533	                                char *bend, int *icount, int *ocount)   );
 13534	_PROTOTYPE( void tty_wakeup, (clock_t now)                              );
 13535	_PROTOTYPE( void tty_reply, (int code, int replyee, int proc_nr,
 13536	                                                        int status)     );
 13537	_PROTOTYPE( int tty_devnop, (struct tty *tp, int try)                   );
 13538	_PROTOTYPE( int select_try, (struct tty *tp, int ops)                   );
 13539	_PROTOTYPE( int select_retry, (struct tty *tp)                          );
 13540	
 13541	/* console.c */
 13542	_PROTOTYPE( void kputc, (int c)                                         );
 13543	_PROTOTYPE( void cons_stop, (void)                                      );
 13544	_PROTOTYPE( void do_new_kmess, (message *m)                             );
 13545	_PROTOTYPE( void do_diagnostics, (message *m)                           );
 13546	_PROTOTYPE( void scr_init, (struct tty *tp)                             );
 13547	_PROTOTYPE( void toggle_scroll, (void)                                  );
 13548	_PROTOTYPE( int con_loadfont, (message *m)                              );
 13549	_PROTOTYPE( void select_console, (int cons_line)                        );
 13550	
 13551	/* keyboard.c */
 13552	_PROTOTYPE( void kb_init, (struct tty *tp)                              );
 13553	_PROTOTYPE( void kb_init_once, (void)                                   );
 13554	_PROTOTYPE( int kbd_loadmap, (message *m)                               );
 13555	_PROTOTYPE( void do_panic_dumps, (message *m)                           );
 13556	_PROTOTYPE( void do_fkey_ctl, (message *m)                              );
 13557	_PROTOTYPE( void kbd_interrupt, (message *m)                            );
 13558	
 13559	/* vidcopy.s */
 13560	_PROTOTYPE( void vid_vid_copy, (unsigned src, unsigned dst, unsigned count));
 13561	_PROTOTYPE( void mem_vid_copy, (u16_t *src, unsigned dst, unsigned count));




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      drivers/tty/tty.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 13600	/* Этот файл содержит драйвер терминала как для IBM-консоли, так и для обычных
 13601	 * ASCII-терминалов. Он обрабатывает только часть терминала, независимую от устройства, а
 13602	 * зависимые от устройства фрагменты кода находятся в файлах console.c, rs232.c и др. Этот
 13603	 * файл содержит две основные точки входа, tty_task() и tty_wakeup(), а также несколько
 13604	 * дополнительных точек входа для использования зависимым от устройств кодом.
 13605	 *
 13606	 * Независимая от устройств часть от зависимой принимает "клавиатурный" ввод, 
 13607	 * выполняет его обработку (интерпретацию специальных клавиш) и
 13608	 * посылает ввод процессу, читающему из терминала. Вывод на терминал передается
 13609	 * зависимому от устройств коду для обработки и "экранного" отображения. Входную
 13610	 * обработку осуществляет устройство, вызывая функцию 'in_process' для входных символов,
 13611	 * а выходная обработка выполняется либо устройством, либо при помощи функции
 13612	 * 'out_process'. Терминал отвечает за работу с входной очередью, а устройство - за
 13613	 * работу с выходной очередью. Если устройство получает внешний сигнал, например,
 13614	 * прерывание, оно обращается к заданию CLOCK для запуска функции tty_wakeup(), которая,
 13615	 * как вы, вероятно, уже догадались, активизирует терминал и проверяет, можно ли продолжить 
 13616	 * ввод или вывод.
 13617	 *
 13618	 * Возможные сообщения и их параметры: 
 13619	 *
 13620	 *   HARD_INT:        вывод завершен или поступил ввод
 13621	 *   SYS_SIG:         например, MINIX собирается завершить работу; запуск кода, выполняющего очистку
 13622	 *   DEV_READ:        процесс собирается выполнить чтение с терминала
 13623	 *   DEV_WRITE:       процесс собирается выполнить запись в терминал
 13624	 *   DEV_IOCTL:       процесс собирается изменить параметры терминала
 13625	 *   DEV_OPEN:        линия терминала открыта
 13626	 *   DEV_CLOSE:       линия терминала закрыта
 13627	 *   DEV_SELECT:      начать выбор запроса на уведомление
 13628	 *   DEV_STATUS:      файловая система собирается получить состояние для SELECT или REVIVE
 13629	 *   CANCEL:          немедленно завершить незаконченный системный вызов
 13630	 *
 13631	 *     m_type       TTY_LINE       PROC_NR      COUNT     TTY_SPEK  TTY_FLAGS  ADDRESS
 13632	 * ---------------------------------------------------------------------------------------
 13633	 * | HARD_INT    |            |             |          |           |          |          |
 13634	 * |-------------+------------+-------------+----------+-----------+----------+----------|
 13635	 * | SYS_SIG     | наб. сигн. |             |          |           |          |          |
 13636	 * |-------------+------------+-------------+----------+-----------+----------+----------|
 13637	 * | DEV_READ    | всп. устр. | номер проц. |  счетчик             O_NONBLOCK |ук-ль буф.|
 13638	 * |-------------+------------+-------------+----------+-----------+----------+----------|
 13639	 * | DEV_WRITE   | всп. устр. | номер проц. |  счетчик |           |          |ук-ль буф.|
 13640	 * |-------------+------------+-------------+----------+-----------+----------+----------|
 13641	 * | DEV_IOCTL   | всп. устр. | номер проц. |код функ. | erase etc |   флаги  |          |
 13642	 * |-------------+------------+-------------+----------+-----------+----------+----------|
 13643	 * | DEV_OPEN    | всп. устр. | номер проц. | O_NOCTTY |           |          |          |
 13644	 * |-------------+------------+-------------+----------+-----------+----------+----------|
 13645	 * | DEV_CLOSE   | всп. устр. | номер проц. |          |           |          |          |
 13646	 * |-------------+------------+-------------+----------+-----------+----------+----------|
 13647	 * | DEV_STATUS  |            |             |          |           |          |          |
 13648	 * |-------------+------------+-------------+----------+-----------+----------+----------|
 13649	 * | CANCEL      | всп. устр. | номер проц. |          |           |          |          |
 13650	 * ---------------------------------------------------------------------------------------
 13651	 *
 13652	 * Изменения: 
 13653	 *   20 янваоя 2004:   драйвер терминала перемещен в пространство пользователя (Jorrit N. Herder)
 13654	 *   20 сентября 2004: локальное управление таймерами / синхронные оповещения (Jorrit N. Herder)
 13655	 *   13 июля 2004:     поддержка для наблюдения за функциональными клавишами (Jorrit N. Herder)  
 13656	 */
 13657	
 13658	#include "../drivers.h"
 13659	#include "../drivers.h"
 13660	#include <termios.h>
 13661	#include <sys/ioc_tty.h>
 13662	#include <signal.h>
 13663	#include <minix/callnr.h>
 13664	#include <minix/keymap.h>
 13665	#include "tty.h"
 13666	
 13667	#include <sys/time.h>
 13668	#include <sys/select.h>
 13669	
 13670	extern int irq_hook_id;
 13671	
 13672	unsigned long kbd_irq_set = 0;
 13673	unsigned long rs_irq_set = 0;
 13674	
 13675	/* Адрес структуры терминала. */
 13676	#define tty_addr(line)  (&tty_table[line])
 13677	
 13678	/* Макросы для магических типов терминала. */
 13679	#define isconsole(tp)   ((tp) < tty_addr(NR_CONS))
 13680	#define ispty(tp)       ((tp) >= tty_addr(NR_CONS+NR_RS_LINES))
 13681	
 13682	/* Макросы для указателей на магические структуры терминалов. */
 13683	#define FIRST_TTY       tty_addr(0)
 13684	#define END_TTY         tty_addr(sizeof(tty_table) / sizeof(tty_table[0]))
 13685	
 13686	/* Устройство существует, если как минимум определена его функция 'devread'. */
 13687	#define tty_active(tp)  ((tp)->tty_devread != NULL)
 13688	
 13689	/* линии RS232 или псевдотерминалы могут быть полностью исключены. */
 13690	#if NR_RS_LINES == 0
 13691	#define rs_init(tp)     ((void) 0)
 13692	#endif
 13693	#if NR_PTYS == 0
 13694	#define pty_init(tp)    ((void) 0)
 13695	#define do_pty(tp, mp)  ((void) 0)
 13696	#endif
 13697	
 13698	FORWARD _PROTOTYPE( void tty_timed_out, (timer_t *tp)                   );
 13699	FORWARD _PROTOTYPE( void expire_timers, (void)                          );
 13700	FORWARD _PROTOTYPE( void settimer, (tty_t *tty_ptr, int enable)         );
 13701	FORWARD _PROTOTYPE( void do_cancel, (tty_t *tp, message *m_ptr)         );
 13702	FORWARD _PROTOTYPE( void do_ioctl, (tty_t *tp, message *m_ptr)          );
 13703	FORWARD _PROTOTYPE( void do_open, (tty_t *tp, message *m_ptr)           );
 13704	FORWARD _PROTOTYPE( void do_close, (tty_t *tp, message *m_ptr)          );
 13705	FORWARD _PROTOTYPE( void do_read, (tty_t *tp, message *m_ptr)           );
 13706	FORWARD _PROTOTYPE( void do_write, (tty_t *tp, message *m_ptr)          );
 13707	FORWARD _PROTOTYPE( void do_select, (tty_t *tp, message *m_ptr)         );
 13708	FORWARD _PROTOTYPE( void do_status, (message *m_ptr)                    );
 13709	FORWARD _PROTOTYPE( void in_transfer, (tty_t *tp)                       );
 13710	FORWARD _PROTOTYPE( int tty_echo, (tty_t *tp, int ch)                   );
 13711	FORWARD _PROTOTYPE( void rawecho, (tty_t *tp, int ch)                   );
 13712	FORWARD _PROTOTYPE( int back_over, (tty_t *tp)                          );
 13713	FORWARD _PROTOTYPE( void reprint, (tty_t *tp)                           );
 13714	FORWARD _PROTOTYPE( void dev_ioctl, (tty_t *tp)                         );
 13715	FORWARD _PROTOTYPE( void setattr, (tty_t *tp)                           );
 13716	FORWARD _PROTOTYPE( void tty_icancel, (tty_t *tp)                       );
 13717	FORWARD _PROTOTYPE( void tty_init, (void)                               );
 13718	
 13719	/* Атрибуты по умолчанию. */
 13720	PRIVATE struct termios termios_defaults = {
 13721	  TINPUT_DEF, TOUTPUT_DEF, TCTRL_DEF, TLOCAL_DEF, TSPEED_DEF, TSPEED_DEF,
 13722	  {
 13723	        TEOF_DEF, TEOL_DEF, TERASE_DEF, TINTR_DEF, TKILL_DEF, TMIN_DEF,
 13724	        TQUIT_DEF, TTIME_DEF, TSUSP_DEF, TSTART_DEF, TSTOP_DEF,
 13725	        TREPRINT_DEF, TLNEXT_DEF, TDISCARD_DEF,
 13726	  },
 13727	};
 13728	PRIVATE struct winsize winsize_defaults;        /* = all zeroes */
 13729	
 13730	/* Глобальные переменные для задания терминала (объявленные внешними в tty.h). */
 13731	PUBLIC tty_t tty_table[NR_CONS+NR_RS_LINES+NR_PTYS];
 13732	PUBLIC int ccurrent;                    /* текущая активная консоль */
 13733	PUBLIC timer_t *tty_timers;             /* очередь таймеров терминала */
 13734	PUBLIC clock_t tty_next_timeout;        /* время следующего оповещения */
 13735	PUBLIC struct machine machine;          /* переменные окружения ядра */
 13736	
 13737	/*===========================================================================*
 13738	 *                              tty_task                                     *
 13739	 *===========================================================================*/
 13740	PUBLIC void main(void)
 13741	{
 13742	/* Главная процедура задания терминала. */
 13743	
 13744	  message tty_mess;             /* буфер для всех входящих сообщений */
 13745	  unsigned line;
 13746	  int s;
 13747	  char *types[] = {"task","driver","server", "user"};
 13748	  register struct proc *rp;
 13749	  register tty_t *tp;
 13750	
 13751	  /* Инициализация драйвера терминала. */
 13752	  tty_init();
 13753	
 13754	  /* Получение окружения ядра (необходимы переменные protected_mode, pc_at и ega). */ 
 13755	  if (OK != (s=sys_getmachine(&machine))) {
 13756	    panic("TTY","Couldn't obtain kernel environment.", s);
 13757	  }
 13758	
 13759	  /* Заключительная единовременная инициализация клавиатуры. */
 13760	  kb_init_once();
 13761	
 13762	  printf("\n");
 13763	
 13764	  while (TRUE) {
 13765	
 13766	        /* Проверка и обработка всех событий всех терминалов. */
 13767	        for (tp = FIRST_TTY; tp < END_TTY; tp++) {
 13768	                if (tp->tty_events) handle_events(tp);
 13769	        }
 13770	
 13771	        /* Получение сообщения-запроса. */
 13772	        receive(ANY, &tty_mess);
 13773	
 13774	        /* Сначала обработка всех уведомлений ядра, поддерживаемых терминалом. 
 13775	         *  - Сработало оповещение – завершить все таймеры и обработать события. 
 13776	         *  - Аппаратное прерывание также является приглашением для проверки событий. 
 13777	         *  - Новое сообщение ядра доступно для печати.
 13778	         *  - Сброс консоли при завершении работы системы.
 13779	         * Далее проверка, отличается ли это сообщение от обычного запроса драйвера
 13780	         * устройства и требует ли отдельной обработки. Дополнительные функции не управляют
 13781	         * устройством, в отличие от запросов драйвера.
 13782	         */
 13783	        switch (tty_mess.m_type) { 
 13784	        case SYN_ALARM:                  /* дальше */
 13785	                expire_timers();        /* запуск сторожевых функций истекших таймеров */
 13786	                continue;               /* продолжение проверки событий */
 13787	        case HARD_INT:  {               /* уведомление об аппаратном прерывании */
 13788	                if (tty_mess.NOTIFY_ARG & kbd_irq_set)
 13789	                        kbd_interrupt(&tty_mess); /* получение символов с клавиатуры */
 13790	#if NR_RS_LINES > 0
 13791	                if (tty_mess.NOTIFY_ARG & rs_irq_set)
 13792	                        rs_interrupt(&tty_mess); /* последовательный ввод-вывод */
 13793	#endif
 13794	                expire_timers();        /* запуск сторожевых функций истекших таймеров */
 13795	                continue;               /* продолжение проверки событий */
 13796	        }
 13797	        case SYS_SIG:  {                /* системный сигнал */
 13798	                sigset_t sigset = (sigset_t) tty_mess.NOTIFY_ARG;
 13799	
 13800	                if (sigismember(&sigset, SIGKSTOP)) {
 13801	                        cons_stop();            /* переключение на главную консоль */
 13802	                        if (irq_hook_id != -1) {
 13803	                                sys_irqdisable(&irq_hook_id);
 13804	                                sys_irqrmpolicy(KEYBOARD_IRQ, &irq_hook_id);
 13805	                        }
 13806	                } 
 13807	                if (sigismember(&sigset, SIGTERM)) cons_stop(); 
 13808	                if (sigismember(&sigset, SIGKMESS)) do_new_kmess(&tty_mess);
 13809	                continue;
 13810	        }
 13811	        case PANIC_DUMPS:               /* разрешение аварийных дампов */
 13812	                cons_stop();            /* переключение на главную консоль */
 13813	                do_panic_dumps(&tty_mess);      
 13814	                continue;
 13815	        case DIAGNOSTICS:               /* сервер собирается что-то напечатать */
 13816	                do_diagnostics(&tty_mess);
 13817	                continue;
 13818	        case FKEY_CONTROL:               /* регистрация/удаление наблюдателя функциональных клавиш */
 13819	                do_fkey_ctl(&tty_mess);
 13820	                continue;
 13821	        default:                        /* должен быть запрос от драйвера */
 13822	                ;                       /* ничего не делать; конец ветвления */
 13823	        }
 13824	
 13825	        /* Здесь должны обрабатываться только запросы устройств. Все запросы, кроме
 13826	         * DEV_STATUS, имеют вспомогательный номер устройства. Проверить это исключение,
 13827	         * в противном случае получить вспомогательный номер устройства.
 13828	         */
 13829	        if (tty_mess.m_type == DEV_STATUS) {
 13830	                do_status(&tty_mess);
 13831	                continue;
 13832	        }
 13833	        line = tty_mess.TTY_LINE;
 13834	        if ((line - CONS_MINOR) < NR_CONS) {
 13835	                tp = tty_addr(line - CONS_MINOR);
 13836	        } else if (line == LOG_MINOR) {
 13837	                tp = tty_addr(0);
 13838	        } else if ((line - RS232_MINOR) < NR_RS_LINES) {
 13839	                tp = tty_addr(line - RS232_MINOR + NR_CONS);
 13840	        } else if ((line - TTYPX_MINOR) < NR_PTYS) {
 13841	                tp = tty_addr(line - TTYPX_MINOR + NR_CONS + NR_RS_LINES);
 13842	        } else if ((line - PTYPX_MINOR) < NR_PTYS) {
 13843	                tp = tty_addr(line - PTYPX_MINOR + NR_CONS + NR_RS_LINES);
 13844	                if (tty_mess.m_type != DEV_IOCTL) {
 13845	                        do_pty(tp, &tty_mess);
 13846	                        continue;
 13847	                }
 13848	        } else {
 13849	                tp = NULL;
 13850	        }
 13851	
 13852	        /* Если устройство не существует или не настроено, возврат ENXIO. */
 13853	        if (tp == NULL || ! tty_active(tp)) {
 13854	                printf("Warning, TTY got illegal request %d from %d\n",
 13855	                        tty_mess.m_type, tty_mess.m_source);
 13856	                tty_reply(TASK_REPLY, tty_mess.m_source,
 13857	                                                tty_mess.PROC_NR, ENXIO);
 13858	                continue;
 13859	        }
 13860	
 13861	        /* Выполнение запрошенной функции драйвера устройства. */
 13862	        switch (tty_mess.m_type) {
 13863	            case DEV_READ:        do_read(tp, &tty_mess);          break;
 13864	            case DEV_WRITE:       do_write(tp, &tty_mess);         break;
 13865	            case DEV_IOCTL:       do_ioctl(tp, &tty_mess);         break;
 13866	            case DEV_OPEN:        do_open(tp, &tty_mess);          break;
 13867	            case DEV_CLOSE:       do_close(tp, &tty_mess);         break;
 13868	            case DEV_SELECT:      do_select(tp, &tty_mess);        break;
 13869	            case CANCEL:          do_cancel(tp, &tty_mess);        break;
 13870	            default:             
 13871	                printf("Warning, TTY got unexpected request %d from %d\n",
 13872	                        tty_mess.m_type, tty_mess.m_source);
 13873	            tty_reply(TASK_REPLY, tty_mess.m_source,
 13874	                                                tty_mess.PROC_NR, EINVAL);
 13875	        }
 13876	  }
 13877	}
	
 13879	/*===========================================================================*
 13880	 *                              do_status                                    *
 13881	 *===========================================================================*/
 13882	PRIVATE void do_status(m_ptr)
 13883	message *m_ptr;
 13884	{
 13885	  register struct tty *tp;
 13886	  int event_found;
 13887	  int status;
 13888	  int ops;
 13889	  
 13890	  /* Проверка событий select и revive для всех терминалов. Если такое событие обнаруживается, 
 13891	   * возвращается одно сообщение состояния. Файловая система сделает другой вызов, чтобы 
 13892	   * проверить, есть ли еще события.
 13893	   */
 13894	  event_found = 0;
 13895	  for (tp = FIRST_TTY; tp < END_TTY; tp++) {
 13896	        if ((ops = select_try(tp, tp->tty_select_ops)) && 
 13897	                        tp->tty_select_proc == m_ptr->m_source) {
 13898	
 13899	                /* ввод-вывод для выбранного вспомогательного устройства готов. */
 13900	                m_ptr->m_type = DEV_IO_READY;
 13901	                m_ptr->DEV_MINOR = tp->tty_index;
 13902	                m_ptr->DEV_SEL_OPS = ops;
 13903	
 13904	                tp->tty_select_ops &= ~ops;     /* снять пометку с события select*/
 13905	                event_found = 1;
 13906	                break;
 13907	        }
 13908	        else if (tp->tty_inrevived && tp->tty_incaller == m_ptr->m_source) {
 13909	                
 13910	                /* Приостановленный запрос завершен. Послать REVIVE. */
 13911	                m_ptr->m_type = DEV_REVIVE;
 13912	                m_ptr->REP_PROC_NR = tp->tty_inproc;
 13913	                m_ptr->REP_STATUS = tp->tty_incum;
 13914	
 13915	                tp->tty_inleft = tp->tty_incum = 0;
 13916	                tp->tty_inrevived = 0;          /* снять пометку с события revive */
 13917	                event_found = 1;
 13918	                break;
 13919	        }
 13920	        else if (tp->tty_outrevived && tp->tty_outcaller == m_ptr->m_source) {
 13921	                
 13922	                /* Приостановленный запрос завершен. Послать REVIVE. */
 13923	                m_ptr->m_type = DEV_REVIVE;
 13924	                m_ptr->REP_PROC_NR = tp->tty_outproc;
 13925	                m_ptr->REP_STATUS = tp->tty_outcum;
 13926	
 13927	                tp->tty_outcum = 0;
 13928	                tp->tty_outrevived = 0;         /* снять пометку с события revive */
 13929	                event_found = 1;
 13930	                break;
 13931	        }
 13932	  }
 13933	
 13934	#if NR_PTYS > 0
 13935	  if (!event_found)
 13936	        event_found = pty_status(m_ptr);
 13937	#endif
 13938	
 13939	  if (! event_found) {
 13940	        /* Интересующих событий не найдено. Возврат пустого сообщения. */
 13941	        m_ptr->m_type = DEV_NO_STATUS;
 13942	  }
 13943	
 13944	  /* Работа почти закончена. Передача ответного сообщения сделавшему вызов процессу. */
 13945	  if ((status = send(m_ptr->m_source, m_ptr)) != OK) {
 13946	        panic("TTY","send in do_status failed, status\n", status);
 13947	  }
 13948	}
	
 13950	/*===========================================================================*
 13951	 *                              do_read                                      *
 13952	 *===========================================================================*/
 13953	PRIVATE void do_read(tp, m_ptr)
 13954	register tty_t *tp;             /* указатель на структуру терминала */
 13955	register message *m_ptr;        /* указатель на сообщение, посылаемое заданию */
 13956	{
 13957	/* Процесс собирается выполнить чтение из терминала. */
 13958	  int r, status;
 13959	  phys_bytes phys_addr;
 13960	
 13961	  /* Проверить, имеется ли процесс, ожидающий чтения, проверить корректность параметров,
 13962	   * выполнить ввод-вывод.
 13963	   */
 13964	  if (tp->tty_inleft > 0) {
 13965	        r = EIO;
 13966	  } else
 13967	  if (m_ptr->COUNT <= 0) {
 13968	        r = EINVAL;
 13969	  } else
 13970	  if (sys_umap(m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT,
 13971	                &phys_addr) != OK) {
 13972	        r = EFAULT;
 13973	  } else {
 13974	        /* Копирование информации из сообщения в структуру терминала. */
 13975	        tp->tty_inrepcode = TASK_REPLY;
 13976	        tp->tty_incaller = m_ptr->m_source;
 13977	        tp->tty_inproc = m_ptr->PROC_NR;
 13978	        tp->tty_in_vir = (vir_bytes) m_ptr->ADDRESS;
 13979	        tp->tty_inleft = m_ptr->COUNT;
 13980	
 13981	        if (!(tp->tty_termios.c_lflag & ICANON)
 13982	                                        && tp->tty_termios.c_cc[VTIME] > 0) {
 13983	                if (tp->tty_termios.c_cc[VMIN] == 0) {
 13984	                        /* MIN и TIME определяют таймер чтения, завершающий операцию чтения
 13985	                         * через TIME/10 секунд, если за это время не поступили новые байты.
 13986	                         */
 13987	                        settimer(tp, TRUE);
 13988	                        tp->tty_min = 1;
 13989	                } else {
 13990	                        /* MIN и TIME определяют межбайтовый таймер, который необходимо
 13991	                         * отменить, если байты еще не поступили.
 13992	                         */
 13993	                        if (tp->tty_eotct == 0) {
 13994	                                settimer(tp, FALSE);
 13995	                                tp->tty_min = tp->tty_termios.c_cc[VMIN];
 13996	                        }
 13997	                }
 13998	        }
 13999	
 14000	        /* Если во входном буфере имеются ожидающие считывания данные, очистить их... */
 14001	        in_transfer(tp);
 14002	        /* ... а затем вернуться за следующей порцией. */
 14003	        handle_events(tp);
 14004	        if (tp->tty_inleft == 0)  {
 14005	                if (tp->tty_select_ops)
 14006	                        select_retry(tp);
 14007	                return;                 /* уже сделано */
 14008	        }
 14009	
 14010	        /* Во входной очереди не было байтов, поэтому вызывающий процесс приостанавливается,
 14011	         * либо чтение прекращается, если является неблокирующим.
 14012	         */
 14013	        if (m_ptr->TTY_FLAGS & O_NONBLOCK) {
 14014	                r = EAGAIN;                             /* отмена чтения */
 14015	                tp->tty_inleft = tp->tty_incum = 0;
 14016	        } else {
 14017	                r = SUSPEND;                            /* приостановка вызывающего процесса */
 14018	                tp->tty_inrepcode = REVIVE;
 14019	        }
 14020	  }
 14021	  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
 14022	  if (tp->tty_select_ops)
 14023	        select_retry(tp);
 14024	}
	
 14026	/*===========================================================================*
 14027	 *                              do_write                                     *
 14028	 *===========================================================================*/
 14029	PRIVATE void do_write(tp, m_ptr)
 14030	register tty_t *tp;
 14031	register message *m_ptr;        /* указатель на сообщение, посылаемое заданию */
 14032	{
 14033	/* Процесс собирается выполнить запись в терминал. */
 14034	  int r;
 14035	  phys_bytes phys_addr;
 14036	
 14037	  /* Проверка наличия процесса, ожидающего чтение, проверка корректности параметров,
 14038	   * выполнение ввода-вывода.
 14039	   */
 14040	  if (tp->tty_outleft > 0) {
 14041	        r = EIO;
 14042	  } else
 14043	  if (m_ptr->COUNT <= 0) {
 14044	        r = EINVAL;
 14045	  } else
 14046	  if (sys_umap(m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, m_ptr->COUNT,
 14047	                &phys_addr) != OK) {
 14048	        r = EFAULT;
 14049	  } else {
 14050	        /* Копирование параметров сообщения в структуру терминала. */
 14051	        tp->tty_outrepcode = TASK_REPLY;
 14052	        tp->tty_outcaller = m_ptr->m_source;
 14053	        tp->tty_outproc = m_ptr->PROC_NR;
 14054	        tp->tty_out_vir = (vir_bytes) m_ptr->ADDRESS;
 14055	        tp->tty_outleft = m_ptr->COUNT;
 14056	
 14057	        /* Попытка записи. */
 14058	        handle_events(tp);
 14059	        if (tp->tty_outleft == 0) 
 14060	                return; /* уже сделано */
 14061	
 14062	        /* не все байты удалось записать, поэтому вызывающий процесс приостанавливается,
 14063	         * либо запись прекращается, если является неблокирующей.
 14064	         */
 14065	        if (m_ptr->TTY_FLAGS & O_NONBLOCK) {            /* отмена записи */
 14066	                r = tp->tty_outcum > 0 ? tp->tty_outcum :  EAGAIN;
 14067	                tp->tty_outleft = tp->tty_outcum = 0;
 14068	        } else {
 14069	                r = SUSPEND;                            /* приостановка вызывающего процесса */
 14070	                tp->tty_outrepcode = REVIVE;
 14071	        }
 14072	  }
 14073	  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
 14074	}
	
 14076	/*===========================================================================*
 14077	 *                              do_ioctl                                     *
 14078	 *===========================================================================*/
 14079	PRIVATE void do_ioctl(tp, m_ptr)
 14080	register tty_t *tp;
 14081	message *m_ptr;                 /* указатель на сообщение, посылаемое заданию */
 14082	{
 14083	/* Выполнение IOCTL на этом терминале. Posix-вызовы termios обрабатываются системным
 14084	 * вызовом IOCTL
 14085	 */
 14086	
 14087	  int r;
 14088	  union {
 14089	        int i;
 14090	  } param;
 14091	  size_t size;
 14092	
 14093	  /* Размер параметра ioctl. */
 14094	  switch (m_ptr->TTY_REQUEST) {
 14095	    case TCGETS:         /* Posix-функция tcgetattr */
 14096	    case TCSETS:         /* Posix-функция tcsetattr, параметр TCSANOW */ 
 14097	    case TCSETSW:        /* Posix-функция tcsetattr, параметр TCSADRAIN */
 14098	    case TCSETSF:        /* Posix-функция tcsetattr, параметр TCSAFLUSH */
 14099	        size = sizeof(struct termios);
 14100	        break;
 14101	
 14102	    case TCSBRK:         /* Posix-функция tcsendbreak */
 14103	    case TCFLOW:         /* Posix-функция tcflow */
 14104	    case TCFLSH:         /* Posix-функция tcflush */
 14105	    case TIOCGPGRP:      /* Posix-функция tcgetpgrp */
 14106	    case TIOCSPGRP:      /* Posix-функция tcsetpgrp */
 14107	        size = sizeof(int);
 14108	        break;
 14109	
 14110	    case TIOCGWINSZ:     /* получение размера окна (не Posix) */
 14111	    case TIOCSWINSZ:     /* задание размера окна (не Posix) */
 14112	        size = sizeof(struct winsize);
 14113	        break;
 14114	
 14115	    case KIOCSMAP:       /* загрузка карты клавиш (расширение Minix) */
 14116	        size = sizeof(keymap_t);
 14117	        break;
 14118	
 14119	    case TIOCSFON:       /* загрузка шрифта (расширение Minix) */
 14120	        size = sizeof(u8_t [8192]);
 14121	        break;
 14122	
 14123	    case TCDRAIN:        /* функция Posix tcdrain – нет параметра */
 14124	    default:             size = 0;
 14125	  }
 14126	
 14127	  r = OK;
 14128	  switch (m_ptr->TTY_REQUEST) {
 14129	    case TCGETS: 
 14130	        /* Получение атрибутов termios. */
 14131	        r = sys_vircopy(SELF, D, (vir_bytes) &tp->tty_termios,
 14132	                m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, 
 14133	                (vir_bytes) size);
 14134	        break;
 14135	
 14136	    case TCSETSW: 
 14137	    case TCSETSF: 
 14138	    case TCDRAIN: 
 14139	        if (tp->tty_outleft > 0) {
 14140	                /* Ожидание окончания всех текущих обработок вывода. */
 14141	                tp->tty_iocaller = m_ptr->m_source;
 14142	                tp->tty_ioproc = m_ptr->PROC_NR;
 14143	                tp->tty_ioreq = m_ptr->REQUEST;
 14144	                tp->tty_iovir = (vir_bytes) m_ptr->ADDRESS;
 14145	                r = SUSPEND;
 14146	                break;
 14147	        }
 14148	        if (m_ptr->TTY_REQUEST == TCDRAIN) break;
 14149	        if (m_ptr->TTY_REQUEST == TCSETSF) tty_icancel(tp);
 14150	        /* дальше */
 14151	    case TCSETS: 
 14152	        /* Установка атрибутов termios. */
 14153	        r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
 14154	                SELF, D, (vir_bytes) &tp->tty_termios, (vir_bytes) size);
 14155	        if (r != OK) break;
 14156	        setattr(tp);
 14157	        break;
 14158	
 14159	    case TCFLSH: 
 14160	        r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
 14161	                SELF, D, (vir_bytes) &param.i, (vir_bytes) size);
 14162	        if (r != OK) break;
 14163	        switch (param.i) {
 14164	            case TCIFLUSH:       tty_icancel(tp);                            break;
 14165	            case TCOFLUSH:       (*tp->tty_ocancel)(tp, 0);                  break;
 14166	            case TCIOFLUSH:      tty_icancel(tp); (*tp->tty_ocancel)(tp, 0); break;
 14167	            default:             r = EINVAL;
 14168	        }
 14169	        break;
 14170	
 14171	    case TCFLOW: 
 14172	        r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
 14173	                SELF, D, (vir_bytes) &param.i, (vir_bytes) size);
 14174	        if (r != OK) break;
 14175	        switch (param.i) {
 14176	            case TCOOFF: 
 14177	            case TCOON: 
 14178	                tp->tty_inhibited = (param.i == TCOOFF);
 14179	                tp->tty_events = 1;
 14180	                break;
 14181	            case TCIOFF: 
 14182	                (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTOP]);
 14183	                break;
 14184	            case TCION: 
 14185	                (*tp->tty_echo)(tp, tp->tty_termios.c_cc[VSTART]);
 14186	                break;
 14187	            default: 
 14188	                r = EINVAL;
 14189	        }
 14190	        break;
 14191	
 14192	    case TCSBRK: 
 14193	        if (tp->tty_break != NULL) (*tp->tty_break)(tp,0);
 14194	        break;
 14195	
 14196	    case TIOCGWINSZ: 
 14197	        r = sys_vircopy(SELF, D, (vir_bytes) &tp->tty_winsize,
 14198	                m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS, 
 14199	                (vir_bytes) size);
 14200	        break;
 14201	
 14202	    case TIOCSWINSZ: 
 14203	        r = sys_vircopy( m_ptr->PROC_NR, D, (vir_bytes) m_ptr->ADDRESS,
 14204	                SELF, D, (vir_bytes) &tp->tty_winsize, (vir_bytes) size);
 14205	        /* SIGWINCH... */
 14206	        break;
 14207	
 14208	    case KIOCSMAP: 
 14209	        /* Загрузка новой карты клавиш (только /dev/console). */
 14210	        if (isconsole(tp)) r = kbd_loadmap(m_ptr);
 14211	        break;
 14212	
 14213	    case TIOCSFON: 
 14214	        /* Загрузка шрифта в карту EGA или VGA (hs@hck.hr) */
 14215	        if (isconsole(tp)) r = con_loadfont(m_ptr);
 14216	        break;
 14217	
 14218	/* Эти функции Posix могут завершаться неудачно, если константа _POSIX_JOB_CONTROL
 14219	 * не определена.
 14220	 */
 14221	    case TIOCGPGRP:      
 14222	    case TIOCSPGRP:      
 14223	    default: 
 14224	        r = ENOTTY;
 14225	  }
 14226	
 14227	  /* Передача ответа. */
 14228	  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
 14229	}
	
 14231	/*===========================================================================*
 14232	 *                              do_open                                      *
 14233	 *===========================================================================*/
 14234	PRIVATE void do_open(tp, m_ptr)
 14235	register tty_t *tp;
 14236	message *m_ptr;                 /* указатель на сообщение, посылаемое заданию */
 14237	{
 14238	/* Линия терминала открыта.  Сделать терминал управляющим, если константа
 14239	 * O_NOCTTY *не* задана и это не устройство журнала.  Если терминал сделан управляющим, 
 14240	 * возвращается 1, в противном случае возвращается OK или код ошибки.
 14241	 */
 14242	  int r = OK;
 14243	
 14244	  if (m_ptr->TTY_LINE == LOG_MINOR) {
 14245	        /* Устройство журнала является диагностическим и предназначено только для записи. */
 14246	        if (m_ptr->COUNT & R_BIT) r = EACCES;
 14247	  } else {
 14248	        if (!(m_ptr->COUNT & O_NOCTTY)) {
 14249	                tp->tty_pgrp = m_ptr->PROC_NR;
 14250	                r = 1;
 14251	        }
 14252	        tp->tty_openct++;
 14253	  }
 14254	  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
 14255	}
	
 14257	/*===========================================================================*
 14258	 *                              do_close                                     *
 14259	 *===========================================================================*/
 14260	PRIVATE void do_close(tp, m_ptr)
 14261	register tty_t *tp;
 14262	message *m_ptr;                 /* указатель на сообщение, посылаемое заданию */
 14263	{
 14264	/* Линия терминала закрыта. Очистить линию, если это закрытие является последним. */
 14265	
 14266	  if (m_ptr->TTY_LINE != LOG_MINOR && --tp->tty_openct == 0) {
 14267	        tp->tty_pgrp = 0;
 14268	        tty_icancel(tp);
 14269	        (*tp->tty_ocancel)(tp, 0);
 14270	        (*tp->tty_close)(tp, 0);
 14271	        tp->tty_termios = termios_defaults;
 14272	        tp->tty_winsize = winsize_defaults;
 14273	        setattr(tp);
 14274	  }
 14275	  tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, OK);
 14276	}
	
 14278	/*===========================================================================*
 14279	 *                              do_cancel                                    *
 14280	 *===========================================================================*/
 14281	PRIVATE void do_cancel(tp, m_ptr)
 14282	register tty_t *tp;
 14283	message *m_ptr;                 /* указатель на сообщение, посылаемое заданию */
 14284	{
 14285	/* Процессу, ожидающему чтения или записи, послан сигнал.
 14286	 * Активная операция чтения или записи должна быть немедленно завершена.
 14287	 */
 14288	
 14289	  int proc_nr;
 14290	  int mode;
 14291	
 14292	  /* Тщательная проверка параметров во избежание повторной отмены. */
 14293	  proc_nr = m_ptr->PROC_NR;
 14294	  mode = m_ptr->COUNT;
 14295	  if ((mode & R_BIT) && tp->tty_inleft != 0 && proc_nr == tp->tty_inproc) {
 14296	        /* Процесс выполнял чтение в момент уничтожения. Очистка ввода. */
 14297	        tty_icancel(tp);
 14298	        tp->tty_inleft = tp->tty_incum = 0;
 14299	  }
 14300	  if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc) {
 14301	        /* Процесс выполнял запись в момент уничтожения. Очистка вывода. */
 14302	        (*tp->tty_ocancel)(tp, 0);
 14303	        tp->tty_outleft = tp->tty_outcum = 0;
 14304	  }
 14305	  if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) {
 14306	        /* Процесс ожидал отправки вывода. */
 14307	        tp->tty_ioreq = 0;
 14308	  }
 14309	  tp->tty_events = 1;
 14310	  tty_reply(TASK_REPLY, m_ptr->m_source, proc_nr, EINTR);
 14311	}
	
 14313	PUBLIC int select_try(struct tty *tp, int ops)
 14314	{
 14315	        int ready_ops = 0;
 14316	
 14317	        /* Особый случай. Если линия закрыта, операции не блокируются.
 14318	         * (см. исключительное условие)
 14319	         */
 14320	        if (tp->tty_termios.c_ospeed == B0) {
 14321	                ready_ops |= ops;
 14322	        }
 14323	
 14324	        if (ops & SEL_RD) {
 14325	                /* будет ли отсутствовать блокирование при чтении? */
 14326	                if (tp->tty_inleft > 0) {
 14327	                        ready_ops |= SEL_RD;    /* EIO - блокирования нет */
 14328	                } else if (tp->tty_incount > 0) {
 14329	                        /* Возможно ли непрерывное чтение? tty_incount показывает
 14330	                         * наличие данных, однако в каноническом режиме чтение продолжится
 14331	                         * только при появлении символа перехода на новую строку.
 14332	                         */
 14333	                        if (!(tp->tty_termios.c_lflag & ICANON) ||
 14334	                                tp->tty_eotct > 0) {
 14335	                                ready_ops |= SEL_RD;
 14336	                        }
 14337	                }
 14338	        }
 14339	
 14340	        if (ops & SEL_WR)  {
 14341	                if (tp->tty_outleft > 0)  ready_ops |= SEL_WR;
 14342	                else if ((*tp->tty_devwrite)(tp, 1)) ready_ops |= SEL_WR;
 14343	        }
 14344	
 14345	        return ready_ops;
 14346	}
	
 14348	PUBLIC int select_retry(struct tty *tp)
 14349	{
 14350	        if (select_try(tp, tp->tty_select_ops))
 14351	                notify(tp->tty_select_proc);
 14352	        return OK;
 14353	}
	
 14355	/*===========================================================================*
 14356	 *                              handle_events                                *
 14357	 *===========================================================================*/
 14358	PUBLIC void handle_events(tp)
 14359	tty_t *tp;                      /* терминал, для которого проверяются события. */
 14360	{
 14361	/* Обработка всех активных событий терминала. Эти события обычно являются прерываниями
 14362	 * от устройств.
 14363	 *
 14364	 * Наиболее важными являются два вида событий:
 14365	 *      - получен символ с консоли или линии RS232.
 14366	 *      - линия RS232 завершила запрос на чтение (от имени пользователя).
 14367	 * Обработчик прерываний может по своему усмотрению задержать сообщение о прерывании, чтобы
 14368	 * избежать перегрузки задания терминала. Если скорость на линиях высока или имеются условия
 14369	 * гонок между входными и выходными линиями, сообщения могут переписываться, так как MINIX
 14370	 * поддерживает один буфер для всех сообщений о прерываниях (в файле proc.c). Каждая линия
 14371	 * явным образом проверяется на наличие нового ввода и завершенного вывода при каждом
 14372	 * прерывании.
 14373	 */
 14374	  char *buf;
 14375	  unsigned count;
 14376	  int status;
 14377	
 14378	  do {
 14379	        tp->tty_events = 0;
 14380	
 14381	        /* Чтение ввода и обработка ввода. */
 14382	        (*tp->tty_devread)(tp, 0);
 14383	
 14384	        /* Обработка вывода и его запись. */
 14385	        (*tp->tty_devwrite)(tp, 0);
 14386	
 14387	        /* Ожидает ли Ioctl какого-либо события? */
 14388	        if (tp->tty_ioreq != 0) dev_ioctl(tp);
 14389	  } while (tp->tty_events);
 14390	
 14391	  /* Передача символов из входной очереди ожидающему их процессу. */
 14392	  in_transfer(tp);
 14393	
 14394	  /* Отправка ответа, если получено достаточное количество байтов. */
 14395	  if (tp->tty_incum >= tp->tty_min && tp->tty_inleft > 0) {
 14396	        if (tp->tty_inrepcode == REVIVE) {
 14397	                notify(tp->tty_incaller);
 14398	                tp->tty_inrevived = 1;
 14399	        } else {
 14400	                tty_reply(tp->tty_inrepcode, tp->tty_incaller, 
 14401	                        tp->tty_inproc, tp->tty_incum);
 14402	                tp->tty_inleft = tp->tty_incum = 0;
 14403	        }
 14404	  }
 14405	  if (tp->tty_select_ops)
 14406	        select_retry(tp);
 14407	#if NR_PTYS > 0
 14408	  if (ispty(tp))
 14409	        select_retry_pty(tp);
 14410	#endif
 14411	}
	
 14413	/*===========================================================================*
 14414	 *                              in_transfer                                  *
 14415	 *===========================================================================*/
 14416	PRIVATE void in_transfer(tp)
 14417	register tty_t *tp;             /* указатель на терминал, из которого осуществляется чтение */
 14418	{
 14419	/* Передача байтов из входной очереди процессу, читающему из терминала. */
 14420	
 14421	  int ch;
 14422	  int count;
 14423	  char buf[64], *bp;
 14424	
 14425	  /* Принудительное чтение, если линия закрыта; для читающего это выглядит подобно концу файла. */
 14426	  if (tp->tty_termios.c_ospeed == B0) tp->tty_min = 0;
 14427	
 14428	  /* Нужно ли что-то делать? */
 14429	  if (tp->tty_inleft == 0 || tp->tty_eotct < tp->tty_min) return;
 14430	
 14431	  bp = buf;
 14432	  while (tp->tty_inleft > 0 && tp->tty_eotct > 0) {
 14433	        ch = *tp->tty_intail;
 14434	
 14435	        if (!(ch & IN_EOF)) {
 14436	                /* Один символ для доставки пользователю. */
 14437	                *bp = ch & IN_CHAR;
 14438	                tp->tty_inleft--;
 14439	                if (++bp == bufend(buf)) {
 14440	                        /* Временный буфер полон, копирование в пространство пользователя. */
 14441	                        sys_vircopy(SELF, D, (vir_bytes) buf, 
 14442	                                tp->tty_inproc, D, tp->tty_in_vir,
 14443	                                (vir_bytes) buflen(buf));
 14444	                        tp->tty_in_vir += buflen(buf);
 14445	                        tp->tty_incum += buflen(buf);
 14446	                        bp = buf;
 14447	                }
 14448	        }
 14449	
 14450	        /* Удаление символа из входной очереди. */
 14451	        if (++tp->tty_intail == bufend(tp->tty_inbuf))
 14452	                tp->tty_intail = tp->tty_inbuf;
 14453	        tp->tty_incount--;
 14454	        if (ch & IN_EOT) {
 14455	                tp->tty_eotct--;
 14456	                /* Не считывать после окончания строки в каноническом режиме. */
 14457	                if (tp->tty_termios.c_lflag & ICANON) tp->tty_inleft = 0;
 14458	        }
 14459	  }
 14460	
 14461	  if (bp > buf) {
 14462	        /* Символы, оставшиеся в буфере. */
 14463	        count = bp - buf;
 14464	        sys_vircopy(SELF, D, (vir_bytes) buf, 
 14465	                tp->tty_inproc, D, tp->tty_in_vir, (vir_bytes) count);
 14466	        tp->tty_in_vir += count;
 14467	        tp->tty_incum += count;
 14468	  }
 14469	
 14470	  /* Обычно ответ посылается пользователю, возможно, даже при incum == 0 (EOF). */
 14471	  if (tp->tty_inleft == 0) {
 14472	        if (tp->tty_inrepcode == REVIVE) {
 14473	                notify(tp->tty_incaller);
 14474	                tp->tty_inrevived = 1;
 14475	        } else {
 14476	                tty_reply(tp->tty_inrepcode, tp->tty_incaller, 
 14477	                        tp->tty_inproc, tp->tty_incum);
 14478	                tp->tty_inleft = tp->tty_incum = 0;
 14479	        }
 14480	  }
 14481	}
	
 14483	/*===========================================================================*
 14484	 *                              in_process                                   *
 14485	 *===========================================================================*/
 14486	PUBLIC int in_process(tp, buf, count)
 14487	register tty_t *tp;             /* терминал, которым получен символ */
 14488	char *buf;                      /* буфер с введенными символами */
 14489	int count;                      /* число введенных символов */
 14490	{
 14491	/* Символы только что были введены. Они обрабатываются, сохраняются и отображаются.
 14492	 * Возврат - число обработанных символов.
 14493	 */
 14494	
 14495	  int ch, sig, ct;
 14496	  int timeset = FALSE;
 14497	  static unsigned char csize_mask[] = { 0x1F, 0x3F, 0x7F, 0xFF };
 14498	
 14499	  for (ct = 0; ct < count; ct++) {
 14500	        /* Выбор одного символа. */
 14501	        ch = *buf++ & BYTE;
 14502	
 14503	        /* Нужно ли сократить до 7 бит? */
 14504	        if (tp->tty_termios.c_iflag & ISTRIP) ch &= 0x7F;
 14505	
 14506	        /* Расширения ввода? */
 14507	        if (tp->tty_termios.c_lflag & IEXTEN) {
 14508	
 14509	                /* Был ли предыдущий символ управляющим? */
 14510	                if (tp->tty_escaped) {
 14511	                        tp->tty_escaped = NOT_ESCAPED;
 14512	                        ch |= IN_ESC;   /* защита символа */
 14513	                }
 14514	
 14515	                /* LNEXT (^V)? */
 14516	                if (ch == tp->tty_termios.c_cc[VLNEXT]) {
 14517	                        tp->tty_escaped = ESCAPED;
 14518	                        rawecho(tp, '^');
 14519	                        rawecho(tp, '\b');
 14520	                        continue;       /* не сохранять управляющий символ */
 14521	                }
 14522	
 14523	                /* REPRINT (^R)? */
 14524	                if (ch == tp->tty_termios.c_cc[VREPRINT]) {
 14525	                        reprint(tp);
 14526	                        continue;
 14527	                }
 14528	        }
 14529	
 14530	        /* _POSIX_VDISABLE - обычный символ, поэтому лучше его обработать. */
 14531	        if (ch == _POSIX_VDISABLE) ch |= IN_ESC;
 14532	
 14533	        /* Преобразование CR в LF, игнорирование CR, либо преобразование LF в CR. */
 14534	        if (ch == '\r') {
 14535	                if (tp->tty_termios.c_iflag & IGNCR) continue;
 14536	                if (tp->tty_termios.c_iflag & ICRNL) ch = '\n';
 14537	        } else
 14538	        if (ch == '\n') {
 14539	                if (tp->tty_termios.c_iflag & INLCR) ch = '\r';
 14540	        }
 14541	
 14542	        /* Канонический режим? */
 14543	        if (tp->tty_termios.c_lflag & ICANON) {
 14544	
 14545	                /* Удаление последнего символа. */
 14546	                if (ch == tp->tty_termios.c_cc[VERASE]) {
 14547	                        (void) back_over(tp);
 14548	                        if (!(tp->tty_termios.c_lflag & ECHOE)) {
 14549	                                (void) tty_echo(tp, ch);
 14550	                        }
 14551	                        continue;
 14552	                }
 14553	
 14554	                /* Удаление текущей строки. */
 14555	                if (ch == tp->tty_termios.c_cc[VKILL]) {
 14556	                        while (back_over(tp)) {}
 14557	                        if (!(tp->tty_termios.c_lflag & ECHOE)) {
 14558	                                (void) tty_echo(tp, ch);
 14559	                                if (tp->tty_termios.c_lflag & ECHOK)
 14560	                                        rawecho(tp, '\n');
 14561	                        }
 14562	                        continue;
 14563	                }
 14564	
 14565	                /* EOF (^D) означает конец файла, невидимый "разрыв строки". */
 14566	                if (ch == tp->tty_termios.c_cc[VEOF]) ch |= IN_EOT | IN_EOF;
 14567	
 14568	                /* Строка может быть возвращена пользователю после LF. */
 14569	                if (ch == '\n') ch |= IN_EOT;
 14570	
 14571	                /* То же с EOL */
 14572	                if (ch == tp->tty_termios.c_cc[VEOL]) ch |= IN_EOT;
 14573	        }
 14574	
 14575	        /* Начать/закончить контроль ввода? */
 14576	        if (tp->tty_termios.c_iflag & IXON) {
 14577	
 14578	                /* Вывод заканчивается на STOP (^S). */
 14579	                if (ch == tp->tty_termios.c_cc[VSTOP]) {
 14580	                        tp->tty_inhibited = STOPPED;
 14581	                        tp->tty_events = 1;
 14582	                        continue;
 14583	                }
 14584	
 14585	                /* Вывод возобновляется на START (^Q) или любом символе при IXANY. */
 14586	                if (tp->tty_inhibited) {
 14587	                        if (ch == tp->tty_termios.c_cc[VSTART]
 14588	                                        || (tp->tty_termios.c_iflag & IXANY)) {
 14589	                                tp->tty_inhibited = RUNNING;
 14590	                                tp->tty_events = 1;
 14591	                                if (ch == tp->tty_termios.c_cc[VSTART])
 14592	                                        continue;
 14593	                        }
 14594	                }
 14595	        }
 14596	
 14597	        if (tp->tty_termios.c_lflag & ISIG) {
 14598	                /* Проверка символов INTR (^?) и QUIT (^\). */
 14599	                if (ch == tp->tty_termios.c_cc[VINTR]
 14600	                                        || ch == tp->tty_termios.c_cc[VQUIT]) {
 14601	                        sig = SIGINT;
 14602	                        if (ch == tp->tty_termios.c_cc[VQUIT]) sig = SIGQUIT;
 14603	                        sigchar(tp, sig);
 14604	                        (void) tty_echo(tp, ch);
 14605	                        continue;
 14606	                }
 14607	        }
 14608	
 14609	        /* Есть ли место во входном буфере? */
 14610	        if (tp->tty_incount == buflen(tp->tty_inbuf)) {
 14611	                /* Места нет; отменить в каноническом режиме, сохранить в "сыром" режиме. */
 14612	                if (tp->tty_termios.c_lflag & ICANON) continue;
 14613	                break;
 14614	        }
 14615	
 14616	        if (!(tp->tty_termios.c_lflag & ICANON)) {
 14617	                /* В "сыром" режиме все символы являются "разрывами строки". */
 14618	                ch |= IN_EOT;
 14619	
 14620	                /* Запустить межбайтовый таймер? */
 14621	                if (!timeset && tp->tty_termios.c_cc[VMIN] > 0
 14622	                                && tp->tty_termios.c_cc[VTIME] > 0) {
 14623	                        settimer(tp, TRUE);
 14624	                        timeset = TRUE;
 14625	                }
 14626	        }
 14627	
 14628	        /* Запутанная функция эхо-отображения. */
 14629	        if (tp->tty_termios.c_lflag & (ECHO|ECHONL)) ch = tty_echo(tp, ch);
 14630	
 14631	        /* Сохранение символа во входной очереди. */
 14632	        *tp->tty_inhead++ = ch;
 14633	        if (tp->tty_inhead == bufend(tp->tty_inbuf))
 14634	                tp->tty_inhead = tp->tty_inbuf;
 14635	        tp->tty_incount++;
 14636	        if (ch & IN_EOT) tp->tty_eotct++;
 14637	
 14638	        /* Попытка завершить ввод, если есть угроза переполнения очереди. */
 14639	        if (tp->tty_incount == buflen(tp->tty_inbuf)) in_transfer(tp);
 14640	  }
 14641	  return ct;
 14642	}
	
 14644	/*===========================================================================*
 14645	 *                              echo                                         *
 14646	 *===========================================================================*/
 14647	PRIVATE int tty_echo(tp, ch)
 14648	register tty_t *tp;             /* терминал, на котором осуществляется эхо-вывод */
 14649	register int ch;                /* указатель на отображаемый символ */
 14650	{
 14651	/* Отображение символа, если включен режим эха. Одни управляющие символы 
 14652	 * отображаются в соответствии с их действием, другие – в виде "^X", обычные
 14653	 * символы отображаются как есть. Символ EOF (^D) отображается, но сразу после
 14654	 * этого происходит его забой.
 14655	 * Возврат: символ с добавлением длины эхо-вывода к его атрибутам.
 14656	 */
 14657	  int len, rp;
 14658	
 14659	  ch &= ~IN_LEN;
 14660	  if (!(tp->tty_termios.c_lflag & ECHO)) {
 14661	        if (ch == ('\n' | IN_EOT) && (tp->tty_termios.c_lflag
 14662	                                        & (ICANON|ECHONL)) == (ICANON|ECHONL))
 14663	                (*tp->tty_echo)(tp, '\n');
 14664	        return(ch);
 14665	  }
 14666	
 14667	  /* "Reprint" указывает, был ли наложен на эхо другой вывод. */
 14668	  rp = tp->tty_incount == 0 ? FALSE :  tp->tty_reprint;
 14669	
 14670	  if ((ch & IN_CHAR) < ' ') {
 14671	        switch (ch & (IN_ESC|IN_EOF|IN_EOT|IN_CHAR)) {
 14672	            case '\t': 
 14673	                len = 0;
 14674	                do {
 14675	                        (*tp->tty_echo)(tp, ' ');
 14676	                        len++;
 14677	                } while (len < TAB_SIZE && (tp->tty_position & TAB_MASK) != 0);
 14678	                break;
 14679	            case '\r' | IN_EOT: 
 14680	            case '\n' | IN_EOT: 
 14681	                (*tp->tty_echo)(tp, ch & IN_CHAR);
 14682	                len = 0;
 14683	                break;
 14684	            default: 
 14685	                (*tp->tty_echo)(tp, '^');
 14686	                (*tp->tty_echo)(tp, '@' + (ch & IN_CHAR));
 14687	                len = 2;
 14688	        }
 14689	  } else
 14690	  if ((ch & IN_CHAR) == '\177') {
 14691	        /* Печатать ли DEL как "^?". */
 14692	        (*tp->tty_echo)(tp, '^');
 14693	        (*tp->tty_echo)(tp, '?');
 14694	        len = 2;
 14695	  } else {
 14696	        (*tp->tty_echo)(tp, ch & IN_CHAR);
 14697	        len = 1;
 14698	  }
 14699	  if (ch & IN_EOF) while (len > 0) { (*tp->tty_echo)(tp, '\b'); len--; }
 14700	
 14701	  tp->tty_reprint = rp;
 14702	  return(ch | (len << IN_LSHIFT));
 14703	}
	
 14705	/*===========================================================================*
 14706	 *                              rawecho                                      *
 14707	 *===========================================================================*/
 14708	PRIVATE void rawecho(tp, ch)
 14709	register tty_t *tp;
 14710	int ch;
 14711	{
 14712	/* Эхо без интерпретации, если установлена константа ECHO. */
 14713	  int rp = tp->tty_reprint;
 14714	  if (tp->tty_termios.c_lflag & ECHO) (*tp->tty_echo)(tp, ch);
 14715	  tp->tty_reprint = rp;
 14716	}
	
 14718	/*===========================================================================*
 14719	 *                              back_over                                    *
 14720	 *===========================================================================*/
 14721	PRIVATE int back_over(tp)
 14722	register tty_t *tp;
 14723	{
 14724	/* Забой и удаление предущего символа. */
 14725	  u16_t *head;
 14726	  int len;
 14727	
 14728	  if (tp->tty_incount == 0) return(0);  /* очередь пуста */
 14729	  head = tp->tty_inhead;
 14730	  if (head == tp->tty_inbuf) head = bufend(tp->tty_inbuf);
 14731	  if (*--head & IN_EOT) return(0);              /* "разрывы строк" нельзя стереть */
 14732	  if (tp->tty_reprint) reprint(tp);             /* повторная печать при наложении */
 14733	  tp->tty_inhead = head;
 14734	  tp->tty_incount--;
 14735	  if (tp->tty_termios.c_lflag & ECHOE) {
 14736	        len = (*head & IN_LEN) >> IN_LSHIFT;
 14737	        while (len > 0) {
 14738	                rawecho(tp, '\b');
 14739	                rawecho(tp, ' ');
 14740	                rawecho(tp, '\b');
 14741	                len--;
 14742	        }
 14743	  }
 14744	  return(1);                            /* один символ удален */
 14745	}
	
 14747	/*===========================================================================*
 14748	 *                              reprint                                      *
 14749	 *===========================================================================*/
 14750	PRIVATE void reprint(tp)
 14751	register tty_t *tp;             /* указатель на структуру терминала */
 14752	{
 14753	/* Восстановление эха на экране, если пользовательский ввод был перекрыт выводом или введен
 14754	 * символ (^R).
 14755	 */
 14756	  int count;
 14757	  u16_t *head;
 14758	
 14759	  tp->tty_reprint = FALSE;
 14760	
 14761	  /* Обнаружение последнего символа конца строки в вводе. */
 14762	  head = tp->tty_inhead;
 14763	  count = tp->tty_incount;
 14764	  while (count > 0) {
 14765	        if (head == tp->tty_inbuf) head = bufend(tp->tty_inbuf);
 14766	        if (head[-1] & IN_EOT) break;
 14767	        head--;
 14768	        count--;
 14769	  }
 14770	  if (count == tp->tty_incount) return;         /* повторная печать не нужна */
 14771	
 14772	  /* Отобразить REPRINT (^R) и переместиться на следующую строку. */
 14773	  (void) tty_echo(tp, tp->tty_termios.c_cc[VREPRINT] | IN_ESC);
 14774	  rawecho(tp, '\r');
 14775	  rawecho(tp, '\n');
 14776	
 14777	  /* Повторная печать с последнего разрыва строки. */
 14778	  do {
 14779	        if (head == bufend(tp->tty_inbuf)) head = tp->tty_inbuf;
 14780	        *head = tty_echo(tp, *head);
 14781	        head++;
 14782	        count++;
 14783	  } while (count < tp->tty_incount);
 14784	}
	
 14786	/*===========================================================================*
 14787	 *                              out_process                                  *
 14788	 *===========================================================================*/
 14789	PUBLIC void out_process(tp, bstart, bpos, bend, icount, ocount)
 14790	tty_t *tp;
 14791	char *bstart, *bpos, *bend;     /* начало/позиция/конец циклического буфера */
 14792	int *icount;                    /* число вводимых/введенных символов */
 14793	int *ocount;                    /* максимальное/текущее число выводимых символов */
 14794	{
 14795	/* Обработка вывода в циклическом буфере. *icount - число обрабатываемых байтов и число байтов,
 14796	 * которые были фактически обработаны (возвращается функцией). *ocount - место, доступное
 14797	 * для ввода и используемое при выводе (*icount < *ocount).
 14798	 * Положение столбца изменяется по модулю размера табуляции.
 14799	 *
 14800	 */
 14801	
 14802	  int tablen;
 14803	  int ict = *icount;
 14804	  int oct = *ocount;
 14805	  int pos = tp->tty_position;
 14806	
 14807	  while (ict > 0) {
 14808	        switch (*bpos) {
 14809	        case '\7': 
 14810	                break;
 14811	        case '\b': 
 14812	                pos--;
 14813	                break;
 14814	        case '\r': 
 14815	                pos = 0;
 14816	                break;
 14817	        case '\n': 
 14818	                if ((tp->tty_termios.c_oflag & (OPOST|ONLCR))
 14819	                                                        == (OPOST|ONLCR)) {
 14820	                        /* Преобразование LF в CR+LF при наличии места. Следующий
 14821	                         * символ в буфере переписывается, поэтому здесь мы
 14822	                         * останавливаемся.
 14823	                         */
 14824	                        if (oct >= 2) {
 14825	                                *bpos = '\r';
 14826	                                if (++bpos == bend) bpos = bstart;
 14827	                                *bpos = '\n';
 14828	                                pos = 0;
 14829	                                ict--;
 14830	                                oct -= 2;
 14831	                        }
 14832	                        goto out_done;  /* ни место, ни буфер не изменились */
 14833	                }
 14834	                break;
 14835	        case '\t': 
 14836	                /* Наилучшее предположение для длины табуляции. */
 14837	                tablen = TAB_SIZE - (pos & TAB_MASK);
 14838	
 14839	                if ((tp->tty_termios.c_oflag & (OPOST|XTABS))
 14840	                                                        == (OPOST|XTABS)) {
 14841	                        /* Табуляции должны быть раскрыты. */
 14842	                        if (oct >= tablen) {
 14843	                                pos += tablen;
 14844	                                ict--;
 14845	                                oct -= tablen;
 14846	                                do {
 14847	                                        *bpos = ' ';
 14848	                                        if (++bpos == bend) bpos = bstart;
 14849	                                } while (--tablen != 0);
 14850	                        }
 14851	                        goto out_done;
 14852	                }
 14853	                /* Прямой вывод табуляций. */
 14854	                pos += tablen;
 14855	                break;
 14856	        default: 
 14857	                /* Считаем, что все остальные символы отображаются как один символ. */
 14858	                pos++;
 14859	        }
 14860	        if (++bpos == bend) bpos = bstart;
 14861	        ict--;
 14862	        oct--;
 14863	  }
 14864	out_done: 
 14865	  tp->tty_position = pos & TAB_MASK;
 14866	
 14867	  *icount -= ict;       /* [io]ct – количества неиспользованных символов */
 14868	  *ocount -= oct;       /* *[io]count –число использованных символов */
 14869	}
	
 14871	/*===========================================================================*
 14872	 *                              dev_ioctl                                    *
 14873	 *===========================================================================*/
 14874	PRIVATE void dev_ioctl(tp)
 14875	tty_t *tp;
 14876	{
 14877	/* TCSETSW, TCSETSF и TCDRAIN ожидают окончания вывода, чтобы гарантировать, что изменение
 14878	 * атрибута не влияет на обработку текущего вывода. После окончания вывода ioctl
 14879	 * исполняется как в do_ioctl().
 14880	 */
 14881	  int result;
 14882	
 14883	  if (tp->tty_outleft > 0) return;              /* вывод не завершен */
 14884	
 14885	  if (tp->tty_ioreq != TCDRAIN) {
 14886	        if (tp->tty_ioreq == TCSETSF) tty_icancel(tp);
 14887	        result = sys_vircopy(tp->tty_ioproc, D, tp->tty_iovir,
 14888	                        SELF, D, (vir_bytes) &tp->tty_termios,
 14889	                        (vir_bytes) sizeof(tp->tty_termios));
 14890	        setattr(tp);
 14891	  }
 14892	  tp->tty_ioreq = 0;
 14893	  tty_reply(REVIVE, tp->tty_iocaller, tp->tty_ioproc, result);
 14894	}
	
 14896	/*===========================================================================*
 14897	 *                              setattr                                      *
 14898	 *===========================================================================*/
 14899	PRIVATE void setattr(tp)
 14900	tty_t *tp;
 14901	{
 14902	/* Применение новых атрибутов линии (сырой/канонический режим, скорость линии и др.) */
 14903	  u16_t *inp;
 14904	  int count;
 14905	
 14906	  if (!(tp->tty_termios.c_lflag & ICANON)) {
 14907	        /* Сырой режим; "разрыв строки" помещается на все символы входной очереди.
 14908	         * То, что происходит с входной очередью при отключении ICANON, не определено;
 14909	         * процессу следует сбросить очередь при помощи TCSAFLUSH.
 14910	         * Тем не менее, хранение опережающего ввода - правильное действие, если процесс
 14911	         * использует TCSANOW для переключения в сырой режим.
 14912	         */
 14913	        count = tp->tty_eotct = tp->tty_incount;
 14914	        inp = tp->tty_intail;
 14915	        while (count > 0) {
 14916	                *inp |= IN_EOT;
 14917	                if (++inp == bufend(tp->tty_inbuf)) inp = tp->tty_inbuf;
 14918	                --count;
 14919	        }
 14920	  }
 14921	
 14922	  /* Проверка MIN и TIME. */
 14923	  settimer(tp, FALSE);
 14924	  if (tp->tty_termios.c_lflag & ICANON) {
 14925	        /* No MIN & TIME in canonical mode. */
 14926	        tp->tty_min = 1;
 14927	  } else {
 14928	        /* В сыром режиме MIN - число ожидаемых символов, а TIME – время ожидания их
 14929	         * ввода, с интересными исключениями, если хотя бы одно из значений нулевое.
 14930	         */
 14931	        tp->tty_min = tp->tty_termios.c_cc[VMIN];
 14932	        if (tp->tty_min == 0 && tp->tty_termios.c_cc[VTIME] > 0)
 14933	                tp->tty_min = 1;
 14934	  }
 14935	
 14936	  if (!(tp->tty_termios.c_iflag & IXON)) {
 14937	        /* Контроль остановки/начала вывода отсутствует, поэтому не подавлять вывод. */
 14938	        tp->tty_inhibited = RUNNING;
 14939	        tp->tty_events = 1;
 14940	  }
 14941	
 14942	  /* Установка скорости вывода в ноль прерывает связь. */
 14943	  if (tp->tty_termios.c_ospeed == B0) sigchar(tp, SIGHUP);
 14944	
 14945	  /* Задание новой скорости линии, размера символа и других параметров на уровне устройства. */
 14946	  (*tp->tty_ioctl)(tp, 0);
 14947	}
	
 14949	/*===========================================================================*
 14950	 *                              tty_reply                                    *
 14951	 *===========================================================================*/
 14952	PUBLIC void tty_reply(code, replyee, proc_nr, status)
 14953	int code;                       /* TASK_REPLY или REVIVE */
 14954	int replyee;                    /* адрес для ответа */
 14955	int proc_nr;                    /* приемник */
 14956	int status;                     /* код ответа */
 14957	{
 14958	/* Отправка ответа процессу, запросившему чтение или запись данных. */
 14959	  message tty_mess;
 14960	
 14961	  tty_mess.m_type = code;
 14962	  tty_mess.REP_PROC_NR = proc_nr;
 14963	  tty_mess.REP_STATUS = status;
 14964	
 14965	  if ((status = send(replyee, &tty_mess)) != OK) {
 14966	        panic("TTY","tty_reply failed, status\n", status);
 14967	  }
 14968	}
	
 14970	/*===========================================================================*
 14971	 *                              sigchar                                      *
 14972	 *===========================================================================*/
 14973	PUBLIC void sigchar(tp, sig)
 14974	register tty_t *tp;
 14975	int sig;                        /* SIGINT, SIGQUIT, SIGKILL или SIGHUP */
 14976	{
 14977	/* Обработка символа SIGINT, SIGQUIT или SIGKILL с клавиатуры, SIGHUP
 14978	 * с терминала, закрытия линии "stty 0" или RS-232. Менеджер процессов 
 14979	 * посылает сигнал группе процессов(INT, QUIT), всем процессам (KILL)
 14980	 * или лидеру сеанса (HUP).
 14981	 */
 14982	  int status;
 14983	
 14984	  if (tp->tty_pgrp != 0) 
 14985	      if (OK != (status = sys_kill(tp->tty_pgrp, sig)))
 14986	        panic("TTY","Error, call to sys_kill failed", status);
 14987	
 14988	  if (!(tp->tty_termios.c_lflag & NOFLSH)) {
 14989	        tp->tty_incount = tp->tty_eotct = 0;    /* уничтожение предшествующего ввода */
 14990	        tp->tty_intail = tp->tty_inhead;
 14991	        (*tp->tty_ocancel)(tp, 0);                      /* уничтожение всего ввода */
 14992	        tp->tty_inhibited = RUNNING;
 14993	        tp->tty_events = 1;
 14994	  }
 14995	}
	
 14997	/*===========================================================================*
 14998	 *                              tty_icancel                                  *
 14999	 *===========================================================================*/
 15000	PRIVATE void tty_icancel(tp)
 15001	register tty_t *tp;
 15002	{
 15003	/* Очистка всего ожидающего ввода, буфера терминала или устройства. */
 15004	
 15005	  tp->tty_incount = tp->tty_eotct = 0;
 15006	  tp->tty_intail = tp->tty_inhead;
 15007	  (*tp->tty_icancel)(tp, 0);
 15008	}
	
 15010	/*===========================================================================*
 15011	 *                              tty_init                                     *
 15012	 *===========================================================================*/
 15013	PRIVATE void tty_init()
 15014	{
 15015	/* Инициализация структуры терминала и вызов процедур инициализации устройства.*/
 15016	
 15017	  register tty_t *tp;
 15018	  int s;
 15019	  struct sigaction sigact;
 15020	
 15021	  /* Инициализация линий терминала. */
 15022	  for (tp = FIRST_TTY,s=0; tp < END_TTY; tp++,s++) {
 15023	
 15024	        tp->tty_index = s;
 15025	
 15026	        tmr_inittimer(&tp->tty_tmr);
 15027	
 15028	        tp->tty_intail = tp->tty_inhead = tp->tty_inbuf;
 15029	        tp->tty_min = 1;
 15030	        tp->tty_termios = termios_defaults;
 15031	        tp->tty_icancel = tp->tty_ocancel = tp->tty_ioctl = tp->tty_close =
 15032	                                                                tty_devnop;
 15033	        if (tp < tty_addr(NR_CONS)) {
 15034	                scr_init(tp);
 15035	                tp->tty_minor = CONS_MINOR + s;
 15036	        } else
 15037	        if (tp < tty_addr(NR_CONS+NR_RS_LINES)) {
 15038	                rs_init(tp);
 15039	                tp->tty_minor = RS232_MINOR + s-NR_CONS;
 15040	        } else {
 15041	                pty_init(tp);
 15042	                tp->tty_minor = s - (NR_CONS+NR_RS_LINES) + TTYPX_MINOR;
 15043	        }
 15044	  }
 15045	}
	
 15047	/*===========================================================================*
 15048	 *                              tty_timed_out                                *
 15049	 *===========================================================================*/
 15050	PRIVATE void tty_timed_out(timer_t *tp)
 15051	{
 15052	/* Этот таймер истек. Установка флага событий для того, чтобы вызвать обработку. */
 15053	  tty_t *tty_ptr;
 15054	  tty_ptr = &tty_table[tmr_arg(tp)->ta_int];
 15055	  tty_ptr->tty_min = 0;                 /* принудительное чтение */
 15056	  tty_ptr->tty_events = 1;              
 15057	}
	
 15059	/*===========================================================================*
 15060	 *                              expire_timers                                *
 15061	 *===========================================================================*/
 15062	PRIVATE void expire_timers(void)
 15063	{
 15064	/* Получено синхронное оповещение. Проверка наличия истекших таймеров. Возможно, установка
 15065	 * флага событий и планирование следующего оповещения.
 15066	 */
 15067	  clock_t now;                          /* текущее время */
 15068	  int s;
 15069	
 15070	  /* Получение текущего времени для сравнения с таймерами. */
 15071	  if ((s=getuptime(&now)) != OK)
 15072	        panic("TTY","Couldn't get uptime from clock.", s);
 15073	
 15074	  /* Сканирование очереди таймеров для обнаружения истекших таймеров. Диспетчеризация
 15075	   * сторожевых функций истекших таймеров. Возможно, требуется запланировать новое оповещение.
 15076	   */
 15077	  tmrs_exptimers(&tty_timers, now, NULL);
 15078	  if (tty_timers == NULL) tty_next_timeout = TMR_NEVER;
 15079	  else {                                          /* задание нового синхронного оповещения */
 15080	        tty_next_timeout = tty_timers->tmr_exp_time;
 15081	        if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
 15082	                panic("TTY","Couldn't set synchronous alarm.", s);
 15083	  }
 15084	}
	
 15086	/*===========================================================================*
 15087	 *                              settimer                                     *
 15088	 *===========================================================================*/
 15089	PRIVATE void settimer(tty_ptr, enable)
 15090	tty_t *tty_ptr;                 /* линия, для которой устанавливается или отменяется таймер */
 15091	int enable;                     /* если true, установить таймер, иначе отменить */
 15092	{
 15093	  clock_t now;                          /* текущее время */
 15094	  clock_t exp_time;
 15095	  int s;
 15096	
 15097	  /* Получение текущего времени для подсчета таймаута. */
 15098	  if ((s=getuptime(&now)) != OK)
 15099	        panic("TTY","Couldn't get uptime from clock.", s);
 15100	  if (enable) {
 15101	        exp_time = now + tty_ptr->tty_termios.c_cc[VTIME] * (HZ/10);
 15102	        /* Set a new timer for enabling the TTY events flags. */
 15103	        tmrs_settimer(&tty_timers, &tty_ptr->tty_tmr, 
 15104	                exp_time, tty_timed_out, NULL);  
 15105	  } else {
 15106	        /* Удаление таймера из списков активных и истекших таймеров. */
 15107	        tmrs_clrtimer(&tty_timers, &tty_ptr->tty_tmr, NULL);
 15108	  }
 15109	  
 15110	  /* Тепеть проверить, следует ли планировать новое оповещение. Это делается, если
 15111	   * таймер, находящийся в начале очереди, был отключен или перемещен в другую позицию,
 15112	   * либо в начало очереди был помещен новый таймер.
 15113	   */
 15114	  if (tty_timers == NULL) tty_next_timeout = TMR_NEVER;
 15115	  else if (tty_timers->tmr_exp_time != tty_next_timeout) { 
 15116	        tty_next_timeout = tty_timers->tmr_exp_time;
 15117	        if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
 15118	                panic("TTY","Couldn't set synchronous alarm.", s);
 15119	  }
 15120	}
	
 15122	/*===========================================================================*
 15123	 *                              tty_devnop                                   *
 15124	 *===========================================================================*/
 15125	PUBLIC int tty_devnop(tp, try)
 15126	tty_t *tp;
 15127	int try;
 15128	{
 15129	  /* Некоторые функции не требуется реализовывать на уровне устройств. */
 15130	}
	
 15132	/*===========================================================================*
 15133	 *                              do_select                                    *
 15134	 *===========================================================================*/
 15135	PRIVATE void do_select(tp, m_ptr)
 15136	register tty_t *tp;             /* указатель на структуру терминала */
 15137	register message *m_ptr;        /* указатель на сообщение, посылаемое заданию */
 15138	{
 15139	        int ops, ready_ops = 0, watch;
 15140	
 15141	        ops = m_ptr->PROC_NR & (SEL_RD|SEL_WR|SEL_ERR);
 15142	        watch = (m_ptr->PROC_NR & SEL_NOTIFY) ? 1 :  0;
 15143	
 15144	        ready_ops = select_try(tp, ops);
 15145	
 15146	        if (!ready_ops && ops && watch) {
 15147	                tp->tty_select_ops |= ops;
 15148	                tp->tty_select_proc = m_ptr->m_source;
 15149	        }
 15150	
 15151	        tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, ready_ops);
 15152	
 15153	        return;
 15154	}





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      drivers/tty/keyboard.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 15200	/* Драйвер клавиатару для PC и AT.
 15201	 *
 15202	 * Изменения:  
 15203	 *   13 июля 2004:  процессы могут вести мониторинг функциональных клавиш (Jorrit N. Herder)
 15204	 *   15 июня 2004:  удалена функция wreboot(), за исключением аварийных дампов (Jorrit N. Herder)
 15205	 *   04 февраля 1994:  загружаемые раскладки клавиатуры (Marcus Hampel)
 15206	 */
 15207	
 15208	#include "../drivers.h"
 15209	#include <sys/time.h>
 15210	#include <sys/select.h>
 15211	#include <termios.h>
 15212	#include <signal.h>
 15213	#include <unistd.h>
 15214	#include <minix/callnr.h>
 15215	#include <minix/com.h>
 15216	#include <minix/keymap.h>
 15217	#include "tty.h"
 15218	#include "keymaps/us-std.src"
 15219	#include "../../kernel/const.h"
 15220	#include "../../kernel/config.h"
 15221	#include "../../kernel/type.h"
 15222	#include "../../kernel/proc.h"
 15223	
 15224	int irq_hook_id = -1;
 15225	
 15226	/* Стандартная и AT-клавиатура.  (PS/2 MCA всюду подразумевает AT) */
 15227	#define KEYBD           0x60    /* порт ввода-вывода для данных клавиатуры */
 15228	
 15229	/* AT-клавиатура. */
 15230	#define KB_COMMAND      0x64    /* порт ввода-вывода для команд AT */
 15231	#define KB_STATUS       0x64    /* порт ввода-вывода для состояния AT */
 15232	#define KB_ACK          0xFA    /* подтверждение от клавиатуры */
 15233	#define KB_OUT_FULL     0x01    /* бит состояния, устанавливаемый при ожидающем нажатии клавиши */
 15234	#define KB_IN_FULL      0x02    /* бит состояния, устанавливаемый при неготовности к приему */
 15235	#define LED_CODE        0xED    /* команда установки индикаторов клавиатуры */
 15236	#define MAX_KB_ACK_RETRIES 0x1000       /* максимальное число попыток подтверждения */
 15237	#define MAX_KB_BUSY_RETRIES 0x1000      /* максимальное число попыток при занятой клавиатуре */
 15238	#define KBIT            0x80    /* бит, используемый для подтверждения символов */
 15239	
 15240	/* Разное. */
 15241	#define ESC_SCAN        0x01    /* клавиша перезагрузки при сбое */
 15242	#define SLASH_SCAN      0x35    /* для распознавания числового слэша */
 15243	#define RSHIFT_SCAN     0x36    /* для различения левой и правой клавиши shift */
 15244	#define HOME_SCAN       0x47    /* первая клавиша на числовой клавиатуре */
 15245	#define INS_SCAN        0x52    /* INS для использования в сочетании CTRL-ALT-INS для перезагрузки */
 15246	#define DEL_SCAN        0x53    /* DEL для использования в сочетании CTRL-ALT-DEL для перезагрузки*/
 15247	
 15248	#define CONSOLE            0    /* номер строки для консоли */
 15249	#define KB_IN_BYTES       32    /* размер входного буфера клавиатуры */
 15250	PRIVATE char ibuf[KB_IN_BYTES]; /* входной буфер */
 15251	PRIVATE char *ihead = ibuf;     /* следующее свободное место во входном буфере */
 15252	PRIVATE char *itail = ibuf;     /* скан-код, возвращаемый терминалу */
 15253	PRIVATE int icount;             /* число кодов в буфере */
 15254	
 15255	PRIVATE int esc;                /* обнаружен скан-код управляющей клавиши? */
 15256	PRIVATE int alt_l;              /* состояние левой клавиши alt */
 15257	PRIVATE int alt_r;              /* состояние правой клавиши alt */
 15258	PRIVATE int alt;                /* любая клавиша alt */
 15259	PRIVATE int ctrl_l;             /* состояние левой клавиши ctrl */
 15260	PRIVATE int ctrl_r;             /* состояние правой клавиши ctrl */
 15261	PRIVATE int ctrl;               /* любая клавиша ctrl */
 15262	PRIVATE int shift_l;            /* состояние левой клавиши shift */
 15263	PRIVATE int shift_r;            /* состояние правой клавиши shift */
 15264	PRIVATE int shift;              /* любая клавиша shift */
 15265	PRIVATE int num_down;           /* клавиша num lock нажата */
 15266	PRIVATE int caps_down;          /* клавиша caps lock нажата */
 15267	PRIVATE int scroll_down;        /* клавиша scroll lock нажата */
 15268	PRIVATE int locks[NR_CONS];     /* состояние клавиш блокировки консоли */
 15269	
 15270	/* Биты активности клавиш блокирования. Эквивалентны битам индикаторов клавиатуры. */
 15271	#define SCROLL_LOCK     0x01
 15272	#define NUM_LOCK        0x02
 15273	#define CAPS_LOCK       0x04
 15274	
 15275	PRIVATE char numpad_map[] =
 15276	                {'H', 'Y', 'A', 'B', 'D', 'C', 'V', 'U', 'G', 'S', 'T', '@'};
 15277	
 15278	/* Переменные и определения наблюдаемых функциональных клавиш. */
 15279	typedef struct observer { int proc_nr; int events; } obs_t;
 15280	PRIVATE obs_t  fkey_obs[12];    /* наблюдатели для F1-F12 */
 15281	PRIVATE obs_t sfkey_obs[12];    /* наблюдатели для SHIFT F1-F12 */
 15282	
 15283	FORWARD _PROTOTYPE( int kb_ack, (void)                                  );
 15284	FORWARD _PROTOTYPE( int kb_wait, (void)                                 );
 15285	FORWARD _PROTOTYPE( int func_key, (int scode)                           );
 15286	FORWARD _PROTOTYPE( int scan_keyboard, (void)                           );
 15287	FORWARD _PROTOTYPE( unsigned make_break, (int scode)                    );
 15288	FORWARD _PROTOTYPE( void set_leds, (void)                               );
 15289	FORWARD _PROTOTYPE( void show_key_mappings, (void)                      );
 15290	FORWARD _PROTOTYPE( int kb_read, (struct tty *tp, int try)              );
 15291	FORWARD _PROTOTYPE( unsigned map_key, (int scode)                       );
 15292	
 15293	/*===========================================================================*
 15294	 *                              map_key0                                     *
 15295	 *===========================================================================*/
 15296	/* Сопоставление скан-кода ASCII-коду, игнорируя модификаторы. */
 15297	#define map_key0(scode)  \
 15298	        ((unsigned) keymap[(scode) * MAP_COLS])
 15299	
 15300	/*===========================================================================*
 15301	 *                              map_key                                      *
 15302	 *===========================================================================*/
 15303	PRIVATE unsigned map_key(scode)
 15304	int scode;
 15305	{
 15306	/* Назначение скан-кода ASCII-коду. */
 15307	
 15308	  int caps, column, lk;
 15309	  u16_t *keyrow;
 15310	
 15311	  if (scode == SLASH_SCAN && esc) return '/';   /* не назначать для числового слэша */
 15312	
 15313	  keyrow = &keymap[scode * MAP_COLS];
 15314	
 15315	  caps = shift;
 15316	  lk = locks[ccurrent];
 15317	  if ((lk & NUM_LOCK) && HOME_SCAN <= scode && scode <= DEL_SCAN) caps = !caps;
 15318	  if ((lk & CAPS_LOCK) && (keyrow[0] & HASCAPS)) caps = !caps;
 15319	
 15320	  if (alt) {
 15321	        column = 2;
 15322	        if (ctrl || alt_r) column = 3;  /* Ctrl + Alt == AltGr */
 15323	        if (caps) column = 4;
 15324	  } else {
 15325	        column = 0;
 15326	        if (caps) column = 1;
 15327	        if (ctrl) column = 5;
 15328	  }
 15329	  return keyrow[column] & ~HASCAPS;
 15330	}
	
 15332	/*===========================================================================*
 15333	 *                              kbd_interrupt                                *
 15334	 *===========================================================================*/
 15335	PUBLIC void kbd_interrupt(m_ptr)
 15336	message *m_ptr;
 15337	{
 15338	/* Произошло прерывание клавиатуры. Его обработка. */
 15339	  int scode;
 15340	  static timer_t timer;         /* таймер должен быть статическим! */
 15341	
 15342	  /* Получение символа от клавиатуры и его подтверждение. */
 15343	  scode = scan_keyboard();
 15344	
 15345	  /* Сохранение скан-кода в памяти, чтобы задание могло использовать его в будущем. */
 15346	  if (icount < KB_IN_BYTES) {
 15347	        *ihead++ = scode;
 15348	        if (ihead == ibuf + KB_IN_BYTES) ihead = ibuf;
 15349	        icount++;
 15350	        tty_table[ccurrent].tty_events = 1;
 15351	        if (tty_table[ccurrent].tty_select_ops & SEL_RD) {
 15352	                select_retry(&tty_table[ccurrent]);
 15353	        }
 15354	  }
 15355	}
	
 15357	/*===========================================================================*
 15358	 *                              kb_read                                      *
 15359	 *===========================================================================*/
 15360	PRIVATE int kb_read(tp, try)
 15361	tty_t *tp;
 15362	int try;
 15363	{
 15364	/* Обработка символов из циклического буфера клавиатуры. */
 15365	  char buf[3];
 15366	  int scode;
 15367	  unsigned ch;
 15368	
 15369	  tp = &tty_table[ccurrent];            /* всегда использовать текущую консоль */
 15370	
 15371	  if (try) {
 15372	        if (icount > 0) return 1;
 15373	        return 0;
 15374	  }
 15375	
 15376	  while (icount > 0) {
 15377	        scode = *itail++;                       /* взять скан-код одной клавиши */
 15378	        if (itail == ibuf + KB_IN_BYTES) itail = ibuf;
 15379	        icount--;
 15380	
 15381	        /* Функциональные клавиши используются для отладочных дампов. */
 15382	        if (func_key(scode)) continue;
 15383	
 15384	        /* Выполнение обработки make/break. */
 15385	        ch = make_break(scode);
 15386	
 15387	        if (ch <= 0xFF) {
 15388	                /* обычный символ. */
 15389	                buf[0] = ch;
 15390	                (void) in_process(tp, buf, 1);
 15391	        } else
 15392	        if (HOME <= ch && ch <= INSRT) {
 15393	                /* Управляющая последовательность, сгенерированная числовой клавиатурой. */
 15394	                buf[0] = ESC;
 15395	                buf[1] = '[';
 15396	                buf[2] = numpad_map[ch - HOME];
 15397	                (void) in_process(tp, buf, 3);
 15398	        } else
 15399	        if (ch == ALEFT) {
 15400	                /* В качестве текущей выбирается консоль с наименьшим номером. */
 15401	                select_console(ccurrent - 1);
 15402	                set_leds();
 15403	        } else
 15404	        if (ch == ARIGHT) {
 15405	                /* Выбор консоли с больщим номеров в качестве текущей. */
 15406	                select_console(ccurrent + 1);
 15407	                set_leds();
 15408	        } else
 15409	        if (AF1 <= ch && ch <= AF12) {
 15410	                /* Alt-F1 - консоль, Alt-F2 - ttyc1 и т. д. */
 15411	                select_console(ch - AF1);
 15412	                set_leds();
 15413	        } else
 15414	        if (CF1 <= ch && ch <= CF12) {
 15415	            switch(ch) {
 15416	                case CF1:  show_key_mappings(); break; 
 15417	                case CF3:  toggle_scroll(); break; /* АО <-> ПО */   
 15418	                case CF7:  sigchar(&tty_table[CONSOLE], SIGQUIT); break;
 15419	                case CF8:  sigchar(&tty_table[CONSOLE], SIGINT); break;
 15420	                case CF9:  sigchar(&tty_table[CONSOLE], SIGKILL); break;
 15421	            }
 15422	        }
 15423	  }
 15424	
 15425	  return 1;
 15426	}
	
 15428	/*===========================================================================*
 15429	 *                              make_break                                   *
 15430	 *===========================================================================*/
 15431	PRIVATE unsigned make_break(scode)
 15432	int scode;                      /* скан-код только что нажатой или отпущенной клавиши */
 15433	{
 15434	/* Эта процедура может работать как с клавиатурами, которые генерируют прерывания только
 15435	 * при нажатии клавиши, так и с клавиатурами, генерирующими прерывания при нажатии и
 15436	 * отпускании. Для эффективности большинство отпусканий игнорируется обработчиком.
 15437	 */
 15438	  int ch, make, escape;
 15439	  static int CAD_count = 0;
 15440	
 15441	  /* Проверка CTRL-ALT-DEL. Если такое сочетание обнаружено, остановить компьютер. Это
 15442	   * лучше сделать в keyboard() на случай зависания терминала, за исключением установки
 15443	   * ctrl и alt в коде более высокого уровня.
 15444	   */
 15445	  if (ctrl && alt && (scode == DEL_SCAN || scode == INS_SCAN))
 15446	  {
 15447	        if (++CAD_count == 3) sys_abort(RBT_HALT);
 15448	        sys_kill(INIT_PROC_NR, SIGABRT);
 15449	        return -1;
 15450	  }
 15451	
 15452	  /* Старший бит установлен при отпускании клавиши. */
 15453	  make = (scode & KEY_RELEASE) == 0;            /* true, если нажата */
 15454	
 15455	  ch = map_key(scode &= ASCII_MASK);            /* сопоставление ASCII */
 15456	
 15457	  escape = esc;         /* клавиша под действием управляющей клавиши?  (true, если добавлена с XT) */
 15458	  esc = 0;
 15459	
 15460	  switch (ch) {
 15461	        case CTRL:               /* Левая или правая клавиша ctrl */
 15462	                *(escape ? &ctrl_r :  &ctrl_l) = make;
 15463	                ctrl = ctrl_l | ctrl_r;
 15464	                break;
 15465	        case SHIFT:              /* Левая или правая клавиша shift */
 15466	                *(scode == RSHIFT_SCAN ? &shift_r :  &shift_l) = make;
 15467	                shift = shift_l | shift_r;
 15468	                break;
 15469	        case ALT:                /* Левая или правая клавиша alt */
 15470	                *(escape ? &alt_r :  &alt_l) = make;
 15471	                alt = alt_l | alt_r;
 15472	                break;
 15473	        case CALOCK:             /* Caps lock – переключение при изменении 0 -> 1 */
 15474	                if (caps_down < make) {
 15475	                        locks[ccurrent] ^= CAPS_LOCK;
 15476	                        set_leds();
 15477	                }
 15478	                caps_down = make;
 15479	                break;
 15480	        case NLOCK:              /* Num lock */
 15481	                if (num_down < make) {
 15482	                        locks[ccurrent] ^= NUM_LOCK;
 15483	                        set_leds();
 15484	                }
 15485	                num_down = make;
 15486	                break;
 15487	        case SLOCK:              /* Scroll lock */
 15488	                if (scroll_down < make) {
 15489	                        locks[ccurrent] ^= SCROLL_LOCK;
 15490	                        set_leds();
 15491	                }
 15492	                scroll_down = make;
 15493	                break;
 15494	        case EXTKEY:             /* управляющая клавиша */
 15495	                esc = 1;         /* следующая клавиша изменяется */
 15496	                return(-1);
 15497	        default:                 /* обычная клавиша */
 15498	                if (make) return(ch);
 15499	  }
 15500	
 15501	  /* Отпускание клавиши или shift-клавиша. */
 15502	  return(-1);
 15503	}
	
 15505	/*===========================================================================*
 15506	 *                              set_leds                                     *
 15507	 *===========================================================================*/
 15508	PRIVATE void set_leds()
 15509	{
 15510	/* Установка индикаторов клавиш caps lock, num lock и scroll lock */
 15511	  int s;
 15512	  if (! machine.pc_at) return;  /* PC/XT не имеют индикаторов */
 15513	
 15514	  kb_wait();                    /* ожидание очистки буфера */
 15515	  if ((s=sys_outb(KEYBD, LED_CODE)) != OK)
 15516	      printf("Warning, sys_outb couldn't prepare for LED values:  %d\n", s);
 15517	                                /* подготовка клавиатуры к принятию кода индикации */
 15518	  kb_ack();                     /* ожидание подтверждения */
 15519	
 15520	  kb_wait();                    /* ожидание очистки буфера */
 15521	  if ((s=sys_outb(KEYBD, locks[ccurrent])) != OK)
 15522	      printf("Warning, sys_outb couldn't give LED values:  %d\n", s);
 15523	                                /* передача кода индикации */
 15524	  kb_ack();                     /* ожидание подтверждения */
 15525	}
	
 15527	/*===========================================================================*
 15528	 *                              kb_wait                                      *
 15529	 *===========================================================================*/
 15530	PRIVATE int kb_wait()
 15531	{
 15532	/* Ожидание готовности контроллера; в случае таймаута возвращается 0. */
 15533	
 15534	  int retries, status, temp;
 15535	  int s;
 15536	
 15537	  retries = MAX_KB_BUSY_RETRIES + 1;    /* ожидание, если контроллер занят */
 15538	  do {
 15539	      s = sys_inb(KB_STATUS, &status);
 15540	      if (status & KB_OUT_FULL) {
 15541	          s = sys_inb(KEYBD, &temp);    /* отмена значения */
 15542	      }
 15543	      if (! (status & (KB_IN_FULL|KB_OUT_FULL)) )
 15544	          break;                        /* ожидание готовности */
 15545	  } while (--retries != 0);             /* продолжать до таймаута */ 
 15546	  return(retries);              /* 0 при таймауте, положительное число при готовности */
 15547	}
	
 15549	/*===========================================================================*
 15550	 *                              kb_ack                                       *
 15551	 *===========================================================================*/
 15552	PRIVATE int kb_ack()
 15553	{
 15554	/* Ожидание подтверждения клавиатурой последней команды; возврат 0 в случае таймаута. */
 15555	
 15556	  int retries, s;
 15557	  u8_t u8val;
 15558	
 15559	  retries = MAX_KB_ACK_RETRIES + 1;
 15560	  do {
 15561	      s = sys_inb(KEYBD, &u8val);
 15562	      if (u8val == KB_ACK)      
 15563	          break;                /* ожидание подтверждения */
 15564	  } while(--retries != 0);      /* продолжение до наступления таймаута */
 15565	
 15566	  return(retries);              /* если подтверждение получено, возвращаем не 0 */
 15567	}
	
 15569	/*===========================================================================*
 15570	 *                              kb_init                                      *
 15571	 *===========================================================================*/
 15572	PUBLIC void kb_init(tp)
 15573	tty_t *tp;
 15574	{
 15575	/* Инициализация драйвера клавиатуры. */
 15576	
 15577	  tp->tty_devread = kb_read;    /* функция ввода */
 15578	}
	
 15580	/*===========================================================================*
 15581	 *                              kb_init_once                                 *
 15582	 *===========================================================================*/
 15583	PUBLIC void kb_init_once(void)
 15584	{
 15585	  int i;
 15586	
 15587	  set_leds();                   /* выключение индикатора numlock */
 15588	  scan_keyboard();              /* отбрасывание оставшегося нажатия клавиши */
 15589	
 15590	      /* Очистка массива наблюдателей за функциональными клавишами. См. также func_key(). */
 15591	      for (i=0; i<12; i++) {
 15592	          fkey_obs[i].proc_nr = NONE;   /* наблюдатели F1-F12 */
 15593	          fkey_obs[i].events = 0;       /* наблюдатели F1-F12 */
 15594	          sfkey_obs[i].proc_nr = NONE;  /* наблюдатели Shift F1-F12 */
 15595	          sfkey_obs[i].events = 0;      /* наблюдатели Shift F1-F12 */
 15596	      }
 15597	
 15598	      /* Задание обработчика прерываний и включение прерывания клавиатуры. */
 15599	      irq_hook_id = KEYBOARD_IRQ;       /* при прерывании нужно вернуть идентификатор */
 15600	      if ((i=sys_irqsetpolicy(KEYBOARD_IRQ, IRQ_REENABLE, &irq_hook_id)) != OK)
 15601	          panic("TTY",  "Couldn't set keyboard IRQ policy", i);
 15602	      if ((i=sys_irqenable(&irq_hook_id)) != OK)
 15603	          panic("TTY", "Couldn't enable keyboard IRQs", i);
 15604	      kbd_irq_set |= (1 << KEYBOARD_IRQ);
 15605	}
	
 15607	/*===========================================================================*
 15608	 *                              kbd_loadmap                                  *
 15609	 *===========================================================================*/
 15610	PUBLIC int kbd_loadmap(m)
 15611	message *m;
 15612	{
 15613	/* Загрузка новой раскладки клавиатуры. */
 15614	  int result;
 15615	  result = sys_vircopy(m->PROC_NR, D, (vir_bytes) m->ADDRESS,
 15616	        SELF, D, (vir_bytes) keymap, 
 15617	        (vir_bytes) sizeof(keymap));
 15618	  return(result);
 15619	}
	
 15621	/*===========================================================================*
 15622	 *                              do_fkey_ctl                                  *
 15623	 *===========================================================================*/
 15624	PUBLIC void do_fkey_ctl(m_ptr)
 15625	message *m_ptr;                 /* указатель на сообщение-запрос */
 15626	{
 15627	/* Эта процедура позволяет процессам регистрировать функциональную клавишу, по нажатии
 15628	 * которой им посылаются уведомления. Клавиша может иметь не более одного сопоставления.
 15629	 */
 15630	  int i; 
 15631	  int result;
 15632	
 15633	  switch (m_ptr->FKEY_REQUEST) {        /* определение того, что мы должны сделать */
 15634	  case FKEY_MAP:                        /* запрос на новую раскладку */
 15635	      result = OK;                      /* предполагаем, что все будет ok*/
 15636	      for (i=0; i < 12; i++) {          /* проверка клавиш F1-F12 */
 15637	          if (bit_isset(m_ptr->FKEY_FKEYS, i+1) ) {
 15638	              if (fkey_obs[i].proc_nr == NONE) { 
 15639	                  fkey_obs[i].proc_nr = m_ptr->m_source;
 15640	                  fkey_obs[i].events = 0;
 15641	                  bit_unset(m_ptr->FKEY_FKEYS, i+1);
 15642	              } else {
 15643	                  printf("WARNING, fkey_map failed F%d\n", i+1);
 15644	                  result = EBUSY;       /* неудача, но попробуем сделать остальное */
 15645	              }
 15646	          }
 15647	      }
 15648	      for (i=0; i < 12; i++) {          /* проверка клавиш Shift+F1-F12 */
 15649	          if (bit_isset(m_ptr->FKEY_SFKEYS, i+1) ) {
 15650	              if (sfkey_obs[i].proc_nr == NONE) { 
 15651	                  sfkey_obs[i].proc_nr = m_ptr->m_source;
 15652	                  sfkey_obs[i].events = 0;
 15653	                  bit_unset(m_ptr->FKEY_SFKEYS, i+1);
 15654	              } else {
 15655	                  printf("WARNING, fkey_map failed Shift F%d\n", i+1);
 15656	                  result = EBUSY;       /* неудача, но попробуем сделать остальное */
 15657	              }
 15658	          }
 15659	      }
 15660	      break;
 15661	  case FKEY_UNMAP: 
 15662	      result = OK;                      /* предполагаем, что все будет ok*/
 15663	      for (i=0; i < 12; i++) {          /* проверка клавиш F1-F12 */
 15664	          if (bit_isset(m_ptr->FKEY_FKEYS, i+1) ) {
 15665	              if (fkey_obs[i].proc_nr == m_ptr->m_source) { 
 15666	                  fkey_obs[i].proc_nr = NONE;
 15667	                  fkey_obs[i].events = 0;
 15668	                  bit_unset(m_ptr->FKEY_FKEYS, i+1);
 15669	              } else {
 15670	                  result = EPERM;       /* неудача, но попробуем сделать остальное */
 15671	              }
 15672	          }
 15673	      }
 15674	      for (i=0; i < 12; i++) {          /* проверка клавиш Shift+F1-F12 */
 15675	          if (bit_isset(m_ptr->FKEY_SFKEYS, i+1) ) {
 15676	              if (sfkey_obs[i].proc_nr == m_ptr->m_source) { 
 15677	                  sfkey_obs[i].proc_nr = NONE;
 15678	                  sfkey_obs[i].events = 0;
 15679	                  bit_unset(m_ptr->FKEY_SFKEYS, i+1);
 15680	              } else {
 15681	                  result = EPERM;       /* неудача, но попробуем сделать остальное */
 15682	              }
 15683	          }
 15684	      }
 15685	      break;
 15686	  case FKEY_EVENTS: 
 15687	      m_ptr->FKEY_FKEYS = m_ptr->FKEY_SFKEYS = 0;
 15688	      for (i=0; i < 12; i++) {          /* проверка клавиш (Shift+) F1-F12 */
 15689	          if (fkey_obs[i].proc_nr == m_ptr->m_source) {
 15690	              if (fkey_obs[i].events) { 
 15691	                  bit_set(m_ptr->FKEY_FKEYS, i+1);
 15692	                  fkey_obs[i].events = 0;
 15693	              }
 15694	          }
 15695	          if (sfkey_obs[i].proc_nr == m_ptr->m_source) {
 15696	              if (sfkey_obs[i].events) { 
 15697	                  bit_set(m_ptr->FKEY_SFKEYS, i+1);
 15698	                  sfkey_obs[i].events = 0;
 15699	              }
 15700	          }
 15701	      }
 15702	      break;
 15703	  default: 
 15704	          result =  EINVAL;             /* наблюдение клавиши невозможно */
 15705	  }
 15706	
 15707	  /* Работа почти завершена, возврат результата вызывающему процессу. */
 15708	  m_ptr->m_type = result;
 15709	  send(m_ptr->m_source, m_ptr);
 15710	}
	
 15712	/*===========================================================================*
 15713	 *                              func_key                                     *
 15714	 *===========================================================================*/
 15715	PRIVATE int func_key(scode)
 15716	int scode;                      /* скан-код для функциональной клавиши */
 15717	{
 15718	/* Эта процедура следит за функциональными клавишами с целью отладки. Наблюдатели 
 15719	 * функциональных клавиш хранятся в глобальном массиве. При нажатии клавиши наблюдатель
 15720	 * получает уведомление об этом событии. Инициализация массивов выполняется в kb_init, где
 15721	 * устанавливаются значения NONE, означающие, что наблюдать за клавишей не нужно.
 15722	 * Возвращает FALSE при нажатии клавиши или если клавиша ненаблюдаемая.
 15723	 */
 15724	  message m;
 15725	  int key;
 15726	  int proc_nr;
 15727	  int i,s;
 15728	
 15729	  /* Игнорирование отпускания клавиш. При нажатии клавиши считывается ее полный код. */
 15730	  if (scode & KEY_RELEASE) return(FALSE);       /* отпускание клавиши */
 15731	  key = map_key(scode);                         /* включение модификаторов */
 15732	
 15733	  /* Клавиша нажата; определяем, имеется ли для нее наблюдатель.
 15734	   *           F1-F12   наблюдатели в массиве fkey_obs. 
 15735	   *    SHIFT  F1-F12   наблюдатели в массиве sfkey_req. 
 15736	   *    CTRL   F1-F12   зарезервированы (см. kb_read)
 15737	   *    ALT    F1-F12   зарезервированы (см. kb_read)
 15738	   * Другие комбинации не используются. Обратите внимание на то, что комбинации Alt+Shift+F1-F12
 15739	   * уже определены в файле <minix/keymap.h> и их легко расширить в будущем.
 15740	   */
 15741	  if (F1 <= key && key <= F12) {                /* F1-F12 */
 15742	      proc_nr = fkey_obs[key - F1].proc_nr;     
 15743	      fkey_obs[key - F1].events ++ ;    
 15744	  } else if (SF1 <= key && key <= SF12) {       /* Shift F2-F12 */
 15745	      proc_nr = sfkey_obs[key - SF1].proc_nr;   
 15746	      sfkey_obs[key - SF1].events ++;   
 15747	  }
 15748	  else {
 15749	      return(FALSE);                            /* клавиша ненаблюдаемая */
 15750	  }
 15751	
 15752	  /* Проверка наличия зарегистрированного наблюдателя и передача ему сообщения. */
 15753	  if (proc_nr != NONE) { 
 15754	      m.NOTIFY_TYPE = FKEY_PRESSED;
 15755	      notify(proc_nr);
 15756	  }
 15757	  return(TRUE);
 15758	}
	
 15760	/*===========================================================================*
 15761	 *                              show_key_mappings                            *
 15762	 *===========================================================================*/
 15763	PRIVATE void show_key_mappings()
 15764	{
 15765	    int i,s;
 15766	    struct proc proc;
 15767	
 15768	    printf("\n");
 15769	    printf("System information.   Known function key mappings to request debug dumps: \n");
 15770	    printf("-------------------------------------------------------------------------\n");
 15771	    for (i=0; i<12; i++) {
 15772	
 15773	      printf(" %sF%d:  ", i+1<10? " ": "", i+1);
 15774	      if (fkey_obs[i].proc_nr != NONE) {
 15775	          if ((s=sys_getproc(&proc, fkey_obs[i].proc_nr))!=OK)
 15776	              printf("sys_getproc:  %d\n", s);
 15777	          printf("%-14.14s", proc.p_name);
 15778	      } else {
 15779	          printf("%-14.14s", "<none>");
 15780	      }
 15781	
 15782	      printf("    %sShift-F%d:  ", i+1<10? " ": "", i+1);
 15783	      if (sfkey_obs[i].proc_nr != NONE) {
 15784	          if ((s=sys_getproc(&proc, sfkey_obs[i].proc_nr))!=OK)
 15785	              printf("sys_getproc:  %d\n", s);
 15786	          printf("%-14.14s", proc.p_name);
 15787	      } else {
 15788	          printf("%-14.14s", "<none>");
 15789	      }
 15790	      printf("\n");
 15791	    }
 15792	    printf("\n");
 15793	    printf("Press one of the registered function keys to trigger a debug dump.\n");
 15794	    printf("\n");
 15795	}
	
 15797	/*===========================================================================*
 15798	 *                              scan_keyboard                                *
 15799	 *===========================================================================*/
 15800	PRIVATE int scan_keyboard()
 15801	{
 15802	/* Получение символа с клавиатуры и его подтверждение. */
 15803	  pvb_pair_t byte_in[2], byte_out[2];
 15804	  
 15805	  byte_in[0].port = KEYBD;      /* получение скан-кода клавиши */
 15806	  byte_in[1].port = PORT_B;     /* стробирование клавиатуры для подтверждения символа */
 15807	  sys_vinb(byte_in, 2);         /* запрос фактического ввода */
 15808	
 15809	  pv_set(byte_out[0], PORT_B, byte_in[1].value | KBIT); /* стробирование 1 */
 15810	  pv_set(byte_out[1], PORT_B, byte_in[1].value);        /* стробирование 0 */
 15811	  sys_voutb(byte_out, 2);       /* запрос фактического вывода */
 15812	
 15813	  return(byte_in[0].value);             /* возврат скан-кода */
 15814	}
	
 15816	/*===========================================================================*
 15817	 *                              do_panic_dumps                               *
 15818	 *===========================================================================*/
 15819	PUBLIC void do_panic_dumps(m)
 15820	message *m;                     /* сообщение-запрос, направляемый терминалу */
 15821	{
 15822	/* Ожидание нажатий клавиш для печати отладочной информации и перезагрузки. */
 15823	  int quiet, code;
 15824	
 15825	  /* Сбой! Разрешить отладочные дампы до тех пор, пока пользователь не решит завершить работу. */
 15826	  printf("\nHit ESC to reboot, DEL to shutdown, F-keys for debug dumps\n");
 15827	
 15828	  (void) scan_keyboard();       /* подтверждение всего предыдущего ввода */
 15829	  quiet = scan_keyboard();/* величина покоя (0 на PC, последний код на AT)*/
 15830	  for (;;) {
 15831	        tickdelay(10);
 15832	        /* Если есть ожидающие запросы на неблокирующий вывод. 
 15833	         * Диагностика может потребовать нескольких вызовов printf()s, поэтому делаем ее в цикле.
 15834	         */
 15835	        while (nb_receive(ANY, m) == OK) {
 15836	                switch(m->m_type) {
 15837	                case FKEY_CONTROL:  do_fkey_ctl(m);      break;
 15838	                case SYS_SIG:       do_new_kmess(m);     break;
 15839	                case DIAGNOSTICS:   do_diagnostics(m);   break;
 15840	                default:         ;       /* ничего не делаем */ 
 15841	                }
 15842	                tickdelay(1);           /* разрешаем больше */
 15843	        }
 15844	        code = scan_keyboard();
 15845	        if (code != quiet) {
 15846	                /* Клавиша нажата. */
 15847	                switch (code) {                 /* возможно, выходим из MINIX */
 15848	                case ESC_SCAN:   sys_abort(RBT_REBOOT);  return; 
 15849	                case DEL_SCAN:   sys_abort(RBT_HALT);    return; 
 15850	                }
 15851	                (void) func_key(code);          /* проверка функциональной клавиши */
 15852	                quiet = scan_keyboard();
 15853	        }
 15854	  }
 15855	}
	




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      drivers/tty/console.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 15900	/* Код и данные для драйвера консоли IBM.
 15901	 *
 15902	 * Видеоконтроллер 6845, используемый IBM PC, совместно с процессором задействует видеопамять,
 15903	 * которая находится в банке памяти по адресу 0xB0000. Для контроллера эта память
 15904	 * состоит из 16-разрядных слов. Каждое слово состоит из кода символа, находящегося в
 15905	 * младшем байте, и так называемого байта атрибутов, расположенного в старшем байте.
 15906	 * Процессор напрямую записывает символы в видеопамять и устанавливает два регистра
 15907	 * контроллера 6845, которые определяют источник видео и положение курсора. Источник видео
 15908	 * - это местоположение первого символа в видеопамяти (верхний левый угол). Перемещение
 15909	 * источника видео позволяет быстро осуществлять прокрутку экрана. Некоторые видеоадаптеры
 15910	 * перемещают источник видео циклически, что дает возможность неограниченного перемещения.
 15911	 * В других видеоадаптерах для изменения положения источника видео иногда требуется
 15912	 * перемещать экранную память. Все вычисления, выполняемые над видеопамятью, для простоты
 15913	 * используют адреса слов и не принимают в расчет цикличность. Функции ассемблерной
 15914	 * поддержки преобразуют адреса слов в адреса байтов, а цикличность обеспечивается функцией 
 15915	 * прокрутки.
 15916	 */
 15917	
 15918	#include "../drivers.h"
 15919	#include <termios.h>
 15920	#include <minix/callnr.h>
 15921	#include <minix/com.h>
 15922	#include "tty.h"
 15923	
 15924	#include "../../kernel/const.h"
 15925	#include "../../kernel/config.h"
 15926	#include "../../kernel/type.h"
 15927	
 15928	/* Определения, используемые драйвером консоли. */
 15929	#define MONO_BASE    0xB0000L   /* базовый адрес монохромной видеопамяти */
 15930	#define COLOR_BASE   0xB8000L   /* базовый адрес цветной видеопамяти */
 15931	#define MONO_SIZE     0x1000    /* 4K монохромной видеопамяти */
 15932	#define COLOR_SIZE    0x4000    /* 16K цветной видеопамяти */
 15933	#define EGA_SIZE      0x8000    /* EGA и VGA имеют как минимум 32K */
 15934	#define BLANK_COLOR   0x0700    /* определяет цвет курсора на пустом экране */
 15935	#define SCROLL_UP          0    /* прокрутка вперед */
 15936	#define SCROLL_DOWN        1    /* прокрутка назад */
 15937	#define BLANK_MEM ((u16_t *) 0) /* указывает mem_vid_copy() очистить экран */
 15938	#define CONS_RAM_WORDS    80    /* размер буфера видеопамяти */
 15939	#define MAX_ESC_PARMS      4    /* число разрешенных параметров управляющих последовательностей */
 15940	
 15941	/* Константы, связанные с микросхемами контроллера. */
 15942	#define M_6845         0x3B4    /* порт для монохромного видео 6845 */
 15943	#define C_6845         0x3D4    /* порт для цветного видео 6845 */
 15944	#define INDEX              0    /* индексный регистр 6845 */
 15945	#define DATA               1    /* регистр данных 6845 */
 15946	#define STATUS             6    /* регистр состояния 6845 */
 15947	#define VID_ORG           12    /* регистр источника 6845 */
 15948	#define CURSOR            14    /* регистр курсора 6845 */
 15949	
 15950	/* Бипер. */
 15951	#define BEEP_FREQ     0x0533    /* значение, записываемое в таймер для установки частоты сигнала */
 15952	#define B_TIME             3    /* длина сигнала CTRL-G в тактах*/
 15953	
 15954	/* определения, используемые для управления шрифтами */
 15955	#define GA_SEQUENCER_INDEX      0x3C4
 15956	#define GA_SEQUENCER_DATA       0x3C5
 15957	#define GA_GRAPHICS_INDEX       0x3CE
 15958	#define GA_GRAPHICS_DATA        0x3CF
 15959	#define GA_VIDEO_ADDRESS        0xA0000L
 15960	#define GA_FONT_SIZE            8192
 15961	
 15962	/* Глобальные переменные, используемые драйвером консоли и кодом ассемблерной поддержки. */
 15963	PUBLIC int vid_index;           /* индекс видеосегмента в удаленной карте памяти*/
 15964	PUBLIC u16_t vid_seg;
 15965	PUBLIC vir_bytes vid_off;       /* видеопамять найдена в vid_seg: vid_off */
 15966	PUBLIC unsigned vid_size;       /* 0x2000 для цветной или 0x0800 для монохромной */
 15967	PUBLIC unsigned vid_mask;       /* 0x1FFF для цветной или 0x07FF для монохромной */
 15968	PUBLIC unsigned blank_color = BLANK_COLOR; /* цвет пустого экрана */
 15969	
 15970	/* Закрытые переменные, используемые драйвером консоли. */
 15971	PRIVATE int vid_port;           /* порт ввода-вывода для доступа к 6845 */
 15972	PRIVATE int wrap;               /* имеется ли аппаратная прокрутка? */
 15973	PRIVATE int softscroll;         /* 1 = программная прокрутка, 0 = аппаратная */
 15974	PRIVATE int beeping;            /* есть ли звуковые сигналы? */
 15975	PRIVATE unsigned font_lines;    /* строк шрифта на символ */
 15976	PRIVATE unsigned scr_width;     /* число символов в строке */
 15977	PRIVATE unsigned scr_lines;     /* число строк на экране */
 15978	PRIVATE unsigned scr_size;      /* число символов на экране */
 15979	
 15980	/* данные консоли. */
 15981	typedef struct console {
 15982	  tty_t *c_tty;                 /* структура терминала */
 15983	  int c_column;                 /* текущий номер столбца (0-источник) */
 15984	  int c_row;                    /* текущая строка (0 в верхней части экрана) */
 15985	  int c_rwords;                 /* число слов (не байтов) в выходной очереди */
 15986	  unsigned c_start;             /* начало видеопамяти этой консоли */
 15987	  unsigned c_limit;             /* граница видеопамяти этой консоли */
 15988	  unsigned c_org;               /* расположение в памяти, на которое указывае база 6845 */
 15989	  unsigned c_cur;               /* текущее положение курсора в видеопамяти */
 15990	  unsigned c_attr;              /* атрибут символа */
 15991	  unsigned c_blank;             /* пустой атрибут */
 15992	  char c_reverse;               /* негативное видео */
 15993	  char c_esc_state;             /* 0=normal, 1=ESC, 2=ESC[ */
 15994	  char c_esc_intro;             /* отличительный символ, следующий за ESC */
 15995	  int *c_esc_parmp;             /* указатель на текущий управляющий параметр */
 15996	  int c_esc_parmv[MAX_ESC_PARMS];       /* список управляющих параметров */
 15997	  u16_t c_ramqueue[CONS_RAM_WORDS];     /* буфер для видеопамяти */
 15998	} console_t;
 15999	
 16000	PRIVATE int nr_cons= 1;         /* фактическое число консолей */
 16001	PRIVATE console_t cons_table[NR_CONS];
 16002	PRIVATE console_t *curcons;     /* видимая консоль */
 16003	
 16004	/* Цвет, если используется цветной контроллер. */
 16005	#define color   (vid_port == C_6845)
 16006	
 16007	/* Сопоставление ANSI-цветов и атрибутов, используемых PC */
 16008	PRIVATE int ansi_colors[8] = {0, 4, 2, 6, 1, 5, 3, 7};
 16009	
 16010	/* Структура для управления шрифтами */
 16011	struct sequence {
 16012	        unsigned short index;
 16013	        unsigned char port;
 16014	        unsigned char value;
 16015	};
 16016	
 16017	FORWARD _PROTOTYPE( int cons_write, (struct tty *tp, int try)           );
 16018	FORWARD _PROTOTYPE( void cons_echo, (tty_t *tp, int c)                  );
 16019	FORWARD _PROTOTYPE( void out_char, (console_t *cons, int c)             );
 16020	FORWARD _PROTOTYPE( void putk, (int c)                                  );
 16021	FORWARD _PROTOTYPE( void beep, (void)                                   );
 16022	FORWARD _PROTOTYPE( void do_escape, (console_t *cons, int c)            );
 16023	FORWARD _PROTOTYPE( void flush, (console_t *cons)                       );
 16024	FORWARD _PROTOTYPE( void parse_escape, (console_t *cons, int c)         );
 16025	FORWARD _PROTOTYPE( void scroll_screen, (console_t *cons, int dir)      );
 16026	FORWARD _PROTOTYPE( void set_6845, (int reg, unsigned val)              );
 16027	FORWARD _PROTOTYPE( void get_6845, (int reg, unsigned *val)             );
 16028	FORWARD _PROTOTYPE( void stop_beep, (timer_t *tmrp)                     );
 16029	FORWARD _PROTOTYPE( void cons_org0, (void)                              );
 16030	FORWARD _PROTOTYPE( int ga_program, (struct sequence *seq)              );
 16031	FORWARD _PROTOTYPE( int cons_ioctl, (tty_t *tp, int)                    );
 16032	
 16033	/*===========================================================================*
 16034	 *                              cons_write                                   *
 16035	 *===========================================================================*/
 16036	PRIVATE int cons_write(tp, try)
 16037	register struct tty *tp;        /* указывает, какой терминал должен использоваться */
 16038	int try;
 16039	{
 16040	/* Копирование всех возможных данных в выходную очередь, затем запуск ввода-вывода. На
 16041	 * терминалах с отображением в память, например, консолях IBM, ввод-вывод будет завершен,
 16042	 * а счетчики обновлены. Повторение до тех пор, пока весь ввод-вывод не будет завершен.
 16043	 */
 16044	
 16045	  int count;
 16046	  int result;
 16047	  register char *tbuf;
 16048	  char buf[64];
 16049	  console_t *cons = tp->tty_priv;
 16050	
 16051	  if (try) return 1;    /* мы всегда можем записывать на консоль */
 16052	
 16053	  /* Быстрая проверка отсутствия работы. Ее можно вызывать часто, чтобы не делать
 16054	   * неудобных проверок в других местах.
 16055	   */
 16056	  if ((count = tp->tty_outleft) == 0 || tp->tty_inhibited) return;
 16057	
 16058	  /* Копирование байтов пользователя в buf[]. Выполнение цикла по копиям,
 16059	   * поскольку буфер пользователя может быть значительно больше, чем buf[].
 16060	   */
 16061	  do {
 16062	        if (count > sizeof(buf)) count = sizeof(buf);
 16063	        if ((result = sys_vircopy(tp->tty_outproc, D, tp->tty_out_vir, 
 16064	                        SELF, D, (vir_bytes) buf, (vir_bytes) count)) != OK)
 16065	                break;
 16066	        tbuf = buf;
 16067	
 16068	        /* Обновлении структуры данных терминала. */
 16069	        tp->tty_out_vir += count;
 16070	        tp->tty_outcum += count;
 16071	        tp->tty_outleft -= count;
 16072	
 16073	        /* Вывод каждого байта копии на экран. Вызов функции out_char() 
 16074	         * для обычных символов не выполняется, они помещаются в буфер
 16075	         * напрямую.
 16076	         */
 16077	        do {
 16078	                if ((unsigned) *tbuf < ' ' || cons->c_esc_state > 0
 16079	                        || cons->c_column >= scr_width
 16080	                        || cons->c_rwords >= buflen(cons->c_ramqueue))
 16081	                {
 16082	                        out_char(cons, *tbuf++);
 16083	                } else {
 16084	                        cons->c_ramqueue[cons->c_rwords++] =
 16085	                                        cons->c_attr | (*tbuf++ & BYTE);
 16086	                        cons->c_column++;
 16087	                }
 16088	        } while (--count != 0);
 16089	  } while ((count = tp->tty_outleft) != 0 && !tp->tty_inhibited);
 16090	
 16091	  flush(cons);                  /* вывод содержимого буфера на экран */
 16092	
 16093	  /* Ответ, если весь вывод завершен или произошла ошибка. */
 16094	  if (tp->tty_outleft == 0 || result != OK) {
 16095	        /* вызов REVIVE невозможен. Ввод-вывод на консоль с отображением в память завершен. */
 16096	        tty_reply(tp->tty_outrepcode, tp->tty_outcaller, tp->tty_outproc,
 16097	                                                        tp->tty_outcum);
 16098	        tp->tty_outcum = 0;
 16099	  }
 16100	}
	
 16102	/*===========================================================================*
 16103	 *                              cons_echo                                    *
 16104	 *===========================================================================*/
 16105	PRIVATE void cons_echo(tp, c)
 16106	register tty_t *tp;             /* указатель на структуру терминала */
 16107	int c;                          /* символ для эхо-отображения */
 16108	{
 16109	/* Эхо-отображение ввода с клавиатуры. */
 16110	  console_t *cons = tp->tty_priv;
 16111	
 16112	  out_char(cons, c);
 16113	  flush(cons);
 16114	}
	
 16116	/*===========================================================================*
 16117	 *                              out_char                                     *
 16118	 *===========================================================================*/
 16119	PRIVATE void out_char(cons, c)
 16120	register console_t *cons;       /* указатель на структуру консоли */
 16121	int c;                          /* выводимый символ */
 16122	{
 16123	/* Вывод символа на консоль. Предварительная проверка на управляющие последовательности. */
 16124	  if (cons->c_esc_state > 0) {
 16125	        parse_escape(cons, c);
 16126	        return;
 16127	  }
 16128	
 16129	  switch(c) {
 16130	        case 000:                /* null обычно используется для заполнения */
 16131	                return;         /* лучше ничего не делать */
 16132	
 16133	        case 007:                /* сигнал */
 16134	                flush(cons);    /* печать всех символов, ожидающих вывода */
 16135	                beep();
 16136	                return;
 16137	
 16138	        case '\b':               /* backspace */
 16139	                if (--cons->c_column < 0) {
 16140	                        if (--cons->c_row >= 0) cons->c_column += scr_width;
 16141	                }
 16142	                flush(cons);
 16143	                return;
 16144	
 16145	        case '\n':               /* конец строки */
 16146	                if ((cons->c_tty->tty_termios.c_oflag & (OPOST|ONLCR))
 16147	                                                == (OPOST|ONLCR)) {
 16148	                        cons->c_column = 0;
 16149	                }
 16150	                /* дальше */
 16151	        case 013:                /* CTRL-K */
 16152	        case 014:                /* CTRL-L */
 16153	                if (cons->c_row == scr_lines-1) {
 16154	                        scroll_screen(cons, SCROLL_UP);
 16155	                } else {
 16156	                        cons->c_row++;
 16157	                }
 16158	                flush(cons);
 16159	                return;
 16160	
 16161	        case '\r':               /* возврат каретки */
 16162	                cons->c_column = 0;
 16163	                flush(cons);
 16164	                return;
 16165	
 16166	        case '\t':               /* табуляция */
 16167	                cons->c_column = (cons->c_column + TAB_SIZE) & ~TAB_MASK;
 16168	                if (cons->c_column > scr_width) {
 16169	                        cons->c_column -= scr_width;
 16170	                        if (cons->c_row == scr_lines-1) {
 16171	                                scroll_screen(cons, SCROLL_UP);
 16172	                        } else {
 16173	                                cons->c_row++;
 16174	                        }
 16175	                }
 16176	                flush(cons);
 16177	                return;
 16178	
 16179	        case 033:                /* ESC – начало управляющей последовательности */
 16180	                flush(cons);    /* печать всех символов, ожидающих вывода */
 16181	                cons->c_esc_state = 1;  /* пометка ESC как просмотренного символа */
 16182	                return;
 16183	
 16184	        default:                 /* печатаемые символы хранятся в ramqueue */
 16185	                if (cons->c_column >= scr_width) {
 16186	                        if (!LINEWRAP) return;
 16187	                        if (cons->c_row == scr_lines-1) {
 16188	                                scroll_screen(cons, SCROLL_UP);
 16189	                        } else {
 16190	                                cons->c_row++;
 16191	                        }
 16192	                        cons->c_column = 0;
 16193	                        flush(cons);
 16194	                }
 16195	                if (cons->c_rwords == buflen(cons->c_ramqueue)) flush(cons);
 16196	                cons->c_ramqueue[cons->c_rwords++] = cons->c_attr | (c & BYTE);
 16197	                cons->c_column++;                       /* next column */
 16198	                return;
 16199	  }
 16200	}
	
 16202	/*===========================================================================*
 16203	 *                              scroll_screen                                *
 16204	 *===========================================================================*/
 16205	PRIVATE void scroll_screen(cons, dir)
 16206	register console_t *cons;       /* указатель на структуру консоли */
 16207	int dir;                        /* SCROLL_UP или SCROLL_DOWN */
 16208	{
 16209	  unsigned new_line, new_org, chars;
 16210	
 16211	  flush(cons);
 16212	  chars = scr_size - scr_width;         /* один экран минус одна строка */
 16213	
 16214	  /* Прокрутка экрана является проблемой из-за несовместимостей различных видеокарт.
 16215	   * Этот драйвер поддерживает программную прокрутку (Hercules), аппаратную прокрутку
 16216	   * (монохромные и CGA-платы), а также нециклическую аппаратную прокрутку (EGA-карты).
 16217	   * В последнем случае мы должны убедиться в том, что
 16218	   *            c_start <= c_org && c_org + scr_size <= c_limit
 16219	   * поскольку EGA не поддерживает циклическую прокрутку видеопамяти.
 16220	   */
 16221	  if (dir == SCROLL_UP) {
 16222	        /* Прокрутка на одну строку вверх тремя способами: программно, нециклически, с помощью источника. */
 16223	        if (softscroll) {
 16224	                vid_vid_copy(cons->c_start + scr_width, cons->c_start, chars);
 16225	        } else
 16226	        if (!wrap && cons->c_org + scr_size + scr_width >= cons->c_limit) {
 16227	                vid_vid_copy(cons->c_org + scr_width, cons->c_start, chars);
 16228	                cons->c_org = cons->c_start;
 16229	        } else {
 16230	                cons->c_org = (cons->c_org + scr_width) & vid_mask;
 16231	        }
 16232	        new_line = (cons->c_org + chars) & vid_mask;
 16233	  } else {
 16234	        /* Прокрутка на одну строку вниз тремя способами: программно, нециклически, с помощью источника. */
 16235	        if (softscroll) {
 16236	                vid_vid_copy(cons->c_start, cons->c_start + scr_width, chars);
 16237	        } else
 16238	        if (!wrap && cons->c_org < cons->c_start + scr_width) {
 16239	                new_org = cons->c_limit - scr_size;
 16240	                vid_vid_copy(cons->c_org, new_org + scr_width, chars);
 16241	                cons->c_org = new_org;
 16242	        } else {
 16243	                cons->c_org = (cons->c_org - scr_width) & vid_mask;
 16244	        }
 16245	        new_line = cons->c_org;
 16246	  }
 16247	  /* Создание новой пустой строки внизу или вверху экрана. */
 16248	  blank_color = cons->c_blank;
 16249	  mem_vid_copy(BLANK_MEM, new_line, scr_width);
 16250	
 16251	  /* Изменение источника видео. */
 16252	  if (cons == curcons) set_6845(VID_ORG, cons->c_org);
 16253	  flush(cons);
 16254	}
	
 16256	/*===========================================================================*
 16257	 *                              flush                                        *
 16258	 *===========================================================================*/
 16259	PRIVATE void flush(cons)
 16260	register console_t *cons;       /* указатель на структуру консоли */
 16261	{
 16262	/* Передача символов, находящихся в 'ramqueue', в память экрана, проверка нового
 16263	 * положения курсора, вычисление нового аппаратного положения курсора и его установка.
 16264	 */
 16265	  unsigned cur;
 16266	  tty_t *tp = cons->c_tty;
 16267	
 16268	  /* Передача символов в 'ramqueue' на экран. */
 16269	  if (cons->c_rwords > 0) {
 16270	        mem_vid_copy(cons->c_ramqueue, cons->c_cur, cons->c_rwords);
 16271	        cons->c_rwords = 0;
 16272	
 16273	        /* Терминалу нужно знать текущий столбец и испорчен ли эхо-вывод. */
 16274	        tp->tty_position = cons->c_column;
 16275	        tp->tty_reprint = TRUE;
 16276	  }
 16277	
 16278	  /* Проверка и обновление позиции курсора. */
 16279	  if (cons->c_column < 0) cons->c_column = 0;
 16280	  if (cons->c_column > scr_width) cons->c_column = scr_width;
 16281	  if (cons->c_row < 0) cons->c_row = 0;
 16282	  if (cons->c_row >= scr_lines) cons->c_row = scr_lines - 1;
 16283	  cur = cons->c_org + cons->c_row * scr_width + cons->c_column;
 16284	  if (cur != cons->c_cur) {
 16285	        if (cons == curcons) set_6845(CURSOR, cur);
 16286	        cons->c_cur = cur;
 16287	  }
 16288	}
	
 16290	/*===========================================================================*
 16291	 *                              parse_escape                                 *
 16292	 *===========================================================================*/
 16293	PRIVATE void parse_escape(cons, c)
 16294	register console_t *cons;       /* указатель на структуру консоли */
 16295	char c;                         /* следующий символ в управляющей последовательности */
 16296	{
 16297	/* В настоящее время поддерживаются следующие управляющие последовательности ANSI:
 16298	 * Если параметр n и (или) m опущен, он считается равным 1.
 16299	 *   ESC [nA перемещение вверх на n строк
 16300	 *   ESC [nB перемещение вниз на n строк
 16301	 *   ESC [nC перемещение вниз на n столбцов
 16302	 *   ESC [nD перемещение вниз на n столбцов
 16303	 *   ESC [m;nH" перемещение курсоа в позицию (m,n)
 16304	 *   ESC [J очистка экрана, начиная с позиции курсора
 16305	 *   ESC [K очистка строки, начиная с позиции курсора
 16306	 *   ESC [nL вставка n строк в позиции курсора
 16307	 *   ESC [nM удаление n строк в позиции курсора
 16308	 *   ESC [nP удаление n символов в позиции курсора
 16309	 *   ESC [n@ вставка n символов в позиции курсора
 16310	 *   ESC [nm режим отображения n (0=нормальный, 4=полужирный, 5=мерцание, 7=выворотка)
 16311	 *   ESC M прокрутка экрана назад, если курсор находится в верхней строке
 16312	 */
 16313	
 16314	  switch (cons->c_esc_state) {
 16315	    case 1:                      /* символ ESC просмотрен */
 16316	        cons->c_esc_intro = '\0';
 16317	        cons->c_esc_parmp = bufend(cons->c_esc_parmv);
 16318	        do {
 16319	                *--cons->c_esc_parmp = 0;
 16320	        } while (cons->c_esc_parmp > cons->c_esc_parmv);
 16321	        switch (c) {
 16322	            case '[':    /* Ввод управляющей последовательности */
 16323	                cons->c_esc_intro = c;
 16324	                cons->c_esc_state = 2;
 16325	                break;
 16326	            case 'M':    /* обратный перевод строки */
 16327	                do_escape(cons, c);
 16328	                break;
 16329	            default: 
 16330	                cons->c_esc_state = 0;
 16331	        }
 16332	        break;
 16333	
 16334	    case 2:                      /* символ ESC [ просмотрен */
 16335	        if (c >= '0' && c <= '9') {
 16336	                if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
 16337	                        *cons->c_esc_parmp = *cons->c_esc_parmp * 10 + (c-'0');
 16338	        } else
 16339	        if (c == ';') {
 16340	                if (cons->c_esc_parmp < bufend(cons->c_esc_parmv))
 16341	                        cons->c_esc_parmp++;
 16342	        } else {
 16343	                do_escape(cons, c);
 16344	        }
 16345	        break;
 16346	  }
 16347	}
	
 16349	/*===========================================================================*
 16350	 *                              do_escape                                    *
 16351	 *===========================================================================*/
 16352	PRIVATE void do_escape(cons, c)
 16353	register console_t *cons;       /* указатель на структуру консоли */
 16354	char c;                         /* следующий символ в управляющей последовательности */
 16355	{
 16356	  int value, n;
 16357	  unsigned src, dst, count;
 16358	  int *parmp;
 16359	
 16360	  /* Некоторые из этих действий работают с экранной памятью, поэтому лучше быть оперативным */
 16361	  flush(cons);
 16362	
 16363	  if (cons->c_esc_intro == '\0') {
 16364	        /* Обработка последовательности, начинающейся с ESC */
 16365	        switch (c) {
 16366	            case 'M':            /* обратный перевод строки */
 16367	                if (cons->c_row == 0) {
 16368	                        scroll_screen(cons, SCROLL_DOWN);
 16369	                } else {
 16370	                        cons->c_row--;
 16371	                }
 16372	                flush(cons);
 16373	                break;
 16374	
 16375	            default:  break;
 16376	        }
 16377	  } else
 16378	  if (cons->c_esc_intro == '[') {
 16379	        /* Обработка последовательности, начинающейся с ESC [ и содержащей параметры */
 16380	        value = cons->c_esc_parmv[0];
 16381	        switch (c) {
 16382	            case 'A':            /* ESC [nA перевод вверх на n строк */
 16383	                n = (value == 0 ? 1 :  value);
 16384	                cons->c_row -= n;
 16385	                flush(cons);
 16386	                break;
 16387	
 16388	            case 'B':            /* ESC [nB перевод вниз на n строк */
 16389	                n = (value == 0 ? 1 :  value);
 16390	                cons->c_row += n;
 16391	                flush(cons);
 16392	                break;
 16393	
 16394	            case 'C':            /* ESC [nC перевод вправо на n столбцов */
 16395	                n = (value == 0 ? 1 :  value);
 16396	                cons->c_column += n;
 16397	                flush(cons);
 16398	                break;
 16399	
 16400	            case 'D':            /* ESC [nD перевод влево на n столбцов */
 16401	                n = (value == 0 ? 1 :  value);
 16402	                cons->c_column -= n;
 16403	                flush(cons);
 16404	                break;
 16405	
 16406	            case 'H':            /* ESC [m;nH" перевод курсора в положение (m,n) */
 16407	                cons->c_row = cons->c_esc_parmv[0] - 1;
 16408	                cons->c_column = cons->c_esc_parmv[1] - 1;
 16409	                flush(cons);
 16410	                break;
 16411	
 16412	            case 'J':            /* ESC [sJ очистка дисплея */
 16413	                switch (value) {
 16414	                    case 0:      /* очистка от курсора до конца экрана */
 16415	                        count = scr_size - (cons->c_cur - cons->c_org);
 16416	                        dst = cons->c_cur;
 16417	                        break;
 16418	                    case 1:      /* очистка от начала экрана до курсора */
 16419	                        count = cons->c_cur - cons->c_org;
 16420	                        dst = cons->c_org;
 16421	                        break;
 16422	                    case 2:      /* Очистка всего экрана */
 16423	                        count = scr_size;
 16424	                        dst = cons->c_org;
 16425	                        break;
 16426	                    default:     /* Ничего не делать */
 16427	                        count = 0;
 16428	                        dst = cons->c_org;
 16429	                }
 16430	                blank_color = cons->c_blank;
 16431	                mem_vid_copy(BLANK_MEM, dst, count);
 16432	                break;
 16433	
 16434	            case 'K':            /* ESC [sK очистка строки от курсора */
 16435	                switch (value) {
 16436	                    case 0:      /* очистка строки, начиная с курсора */
 16437	                        count = scr_width - cons->c_column;
 16438	                        dst = cons->c_cur;
 16439	                        break;
 16440	                    case 1:      /* очистка от начала строки до курсора */
 16441	                        count = cons->c_column;
 16442	                        dst = cons->c_cur - cons->c_column;
 16443	                        break;
 16444	                    case 2:      /* очистка всей строки */
 16445	                        count = scr_width;
 16446	                        dst = cons->c_cur - cons->c_column;
 16447	                        break;
 16448	                    default:     /* ничего не делать */
 16449	                        count = 0;
 16450	                        dst = cons->c_cur;
 16451	                }
 16452	                blank_color = cons->c_blank;
 16453	                mem_vid_copy(BLANK_MEM, dst, count);
 16454	                break;
 16455	
 16456	            case 'L':            /* ESC [nL вставка n строк в позиции курсора */
 16457	                n = value;
 16458	                if (n < 1) n = 1;
 16459	                if (n > (scr_lines - cons->c_row))
 16460	                        n = scr_lines - cons->c_row;
 16461	
 16462	                src = cons->c_org + cons->c_row * scr_width;
 16463	                dst = src + n * scr_width;
 16464	                count = (scr_lines - cons->c_row - n) * scr_width;
 16465	                vid_vid_copy(src, dst, count);
 16466	                blank_color = cons->c_blank;
 16467	                mem_vid_copy(BLANK_MEM, src, n * scr_width);
 16468	                break;
 16469	
 16470	            case 'M':            /* ESC [nM удаление n строк в позиции курсора */
 16471	                n = value;
 16472	                if (n < 1) n = 1;
 16473	                if (n > (scr_lines - cons->c_row))
 16474	                        n = scr_lines - cons->c_row;
 16475	
 16476	                dst = cons->c_org + cons->c_row * scr_width;
 16477	                src = dst + n * scr_width;
 16478	                count = (scr_lines - cons->c_row - n) * scr_width;
 16479	                vid_vid_copy(src, dst, count);
 16480	                blank_color = cons->c_blank;
 16481	                mem_vid_copy(BLANK_MEM, dst + count, n * scr_width);
 16482	                break;
 16483	
 16484	            case '@':            /* ESC [n@ вставка n символов в позиции курсора */
 16485	                n = value;
 16486	                if (n < 1) n = 1;
 16487	                if (n > (scr_width - cons->c_column))
 16488	                        n = scr_width - cons->c_column;
 16489	
 16490	                src = cons->c_cur;
 16491	                dst = src + n;
 16492	                count = scr_width - cons->c_column - n;
 16493	                vid_vid_copy(src, dst, count);
 16494	                blank_color = cons->c_blank;
 16495	                mem_vid_copy(BLANK_MEM, src, n);
 16496	                break;
 16497	
 16498	            case 'P':            /* ESC [nP удаление n символов в позиции курсора */
 16499	                n = value;
 16500	                if (n < 1) n = 1;
 16501	                if (n > (scr_width - cons->c_column))
 16502	                        n = scr_width - cons->c_column;
 16503	
 16504	                dst = cons->c_cur;
 16505	                src = dst + n;
 16506	                count = scr_width - cons->c_column - n;
 16507	                vid_vid_copy(src, dst, count);
 16508	                blank_color = cons->c_blank;
 16509	                mem_vid_copy(BLANK_MEM, dst + count, n);
 16510	                break;
 16511	
 16512	            case 'm':            /* ESC [nm задание режима отображения n */
 16513	                for (parmp = cons->c_esc_parmv; parmp <= cons->c_esc_parmp
 16514	                                && parmp < bufend(cons->c_esc_parmv); parmp++) {
 16515	                        if (cons->c_reverse) {
 16516	                                /* возврат fg- и bg-цветов */
 16517	                                cons->c_attr =  ((cons->c_attr & 0x7000) >> 4) |
 16518	                                                ((cons->c_attr & 0x0700) << 4) |
 16519	                                                ((cons->c_attr & 0x8800));
 16520	                        }
 16521	                        switch (n = *parmp) {
 16522	                            case 0:      /* NORMAL */
 16523	                                cons->c_attr = cons->c_blank = BLANK_COLOR;
 16524	                                cons->c_reverse = FALSE;
 16525	                                break;
 16526	
 16527	                            case 1:      /* полужирный  */
 16528	                                /* установка бита интенсивности */
 16529	                                cons->c_attr |= 0x0800;
 16530	                                break;
 16531	
 16532	                            case 4:      /* подчеркивание */
 16533	                                if (color) {
 16534	                                        /* изменение белого цвета на голубой, то есть удаление красного
 16535	                                         */
 16536	                                        cons->c_attr = (cons->c_attr & 0xBBFF);
 16537	                                } else {
 16538	                                        /* установка атрибута подчеркивания */
 16539	                                        cons->c_attr = (cons->c_attr & 0x99FF);
 16540	                                }
 16541	                                break;
 16542	
 16543	                            case 5:      /* мерцание */
 16544	                                /* установка бита мерцания */
 16545	                                cons->c_attr |= 0x8000;
 16546	                                break;
 16547	
 16548	                            case 7:      /* выворотка */
 16549	                                cons->c_reverse = TRUE;
 16550	                                break;
 16551	
 16552	                            default:     /* цвет */
 16553	                                if (n == 39) n = 37;    /* установка цвета по умолчанию */
 16554	                                if (n == 49) n = 40;
 16555	
 16556	                                if (!color) {
 16557	                                        /* не смешивать в случае монохромного экрана */
 16558	                                } else
 16559	                                if (30 <= n && n <= 37) {
 16560	                                        /* цвет изображения */
 16561	                                        cons->c_attr =
 16562	                                                (cons->c_attr & 0xF8FF) |
 16563	                                                (ansi_colors[(n - 30)] << 8);
 16564	                                        cons->c_blank =
 16565	                                                (cons->c_blank & 0xF8FF) |
 16566	                                                (ansi_colors[(n - 30)] << 8);
 16567	                                } else
 16568	                                if (40 <= n && n <= 47) {
 16569	                                        /* цвет фона */
 16570	                                        cons->c_attr =
 16571	                                                (cons->c_attr & 0x8FFF) |
 16572	                                                (ansi_colors[(n - 40)] << 12);
 16573	                                        cons->c_blank =
 16574	                                                (cons->c_blank & 0x8FFF) |
 16575	                                                (ansi_colors[(n - 40)] << 12);
 16576	                                }
 16577	                        }
 16578	                        if (cons->c_reverse) {
 16579	                                /* обмен fg- и bg-цветов */
 16580	                                cons->c_attr =  ((cons->c_attr & 0x7000) >> 4) |
 16581	                                                ((cons->c_attr & 0x0700) << 4) |
 16582	                                                ((cons->c_attr & 0x8800));
 16583	                        }
 16584	                }
 16585	                break;
 16586	        }
 16587	  }
 16588	  cons->c_esc_state = 0;
 16589	}
	
 16591	/*===========================================================================*
 16592	 *                              set_6845                                     *
 16593	 *===========================================================================*/
 16594	PRIVATE void set_6845(reg, val)
 16595	int reg;                        /* устанавливаемая пара регистров */
 16596	unsigned val;                   /* устанавливаемое 16-разрядное значение */
 16597	{
 16598	/* Установка пары регистров в контроллере 6845.
 16599	 * Регистры 12-13 указывают начало видеоданных в памяти
 16600	 * Регистры 14-15 указывают, куда поместить курсор
 16601	 */
 16602	  pvb_pair_t char_out[4];
 16603	  pv_set(char_out[0], vid_port + INDEX, reg);   /* установка индексного регистра */
 16604	  pv_set(char_out[1], vid_port + DATA, (val>>8) & BYTE);    /* старший байт */
 16605	  pv_set(char_out[2], vid_port + INDEX, reg + 1);           /* снова */
 16606	  pv_set(char_out[3], vid_port + DATA, val&BYTE);           /* младший байт */
 16607	  sys_voutb(char_out, 4);                       /* фактический вывод */
 16608	}
	
 16610	/*===========================================================================*
 16611	 *                              get_6845                                     *
 16612	 *===========================================================================*/
 16613	PRIVATE void get_6845(reg, val)
 16614	int reg;                        /* устанавливаемая пара регистров */
 16615	unsigned *val;                  /* устанавливаемое 16-разрядное значение */
 16616	{
 16617	  char v1, v2;
 16618	/* Получение пары регистров контроллера 6845.  */
 16619	  sys_outb(vid_port + INDEX, reg); 
 16620	  sys_inb(vid_port + DATA, &v1); 
 16621	  sys_outb(vid_port + INDEX, reg+1); 
 16622	  sys_inb(vid_port + DATA, &v2); 
 16623	  *val = (v1 << 8) | v2;
 16624	}
	
 16626	/*===========================================================================*
 16627	 *                              beep                                         *
 16628	 *===========================================================================*/
 16629	PRIVATE void beep()
 16630	{
 16631	/* Подача сигнала с помощью динамика (вывод CRTL-G).
 16632	 * Эта процедура изменяет значения битов 0 и 1 порта B микросхемы 8255,
 16633	 * управляющей динамиком.
 16634	 */
 16635	  static timer_t tmr_stop_beep;
 16636	  pvb_pair_t char_out[3];
 16637	  clock_t now;
 16638	  int port_b_val, s;
 16639	  
 16640	  /* Получение текущего времени заранее, чтобы избежать задержки сигнала. */
 16641	  if ((s=getuptime(&now)) != OK)
 16642	        panic("TTY","Console couldn't get clock's uptime.", s);
 16643	  if (!beeping) {
 16644	        /* Установка канала 2 таймера, прямоугольный импульс с заданной частотой. */
 16645	        pv_set(char_out[0], TIMER_MODE, 0xB6);  
 16646	        pv_set(char_out[1], TIMER2, (BEEP_FREQ >> 0) & BYTE);
 16647	        pv_set(char_out[2], TIMER2, (BEEP_FREQ >> 8) & BYTE);
 16648	        if (sys_voutb(char_out, 3)==OK) {
 16649	                if (sys_inb(PORT_B, &port_b_val)==OK &&
 16650	                    sys_outb(PORT_B, (port_b_val|3))==OK)
 16651	                        beeping = TRUE;
 16652	        }
 16653	  }
 16654	  /* Добавление таймера в список таймеров. Возможно, перепланирование оповещения. */
 16655	  tmrs_settimer(&tty_timers, &tmr_stop_beep, now+B_TIME, stop_beep, NULL);
 16656	  if (tty_timers->tmr_exp_time != tty_next_timeout) {
 16657	        tty_next_timeout = tty_timers->tmr_exp_time;
 16658	        if ((s=sys_setalarm(tty_next_timeout, 1)) != OK)
 16659	                panic("TTY","Console couldn't set alarm.", s);
 16660	  }
 16661	}
	
 16663	/*===========================================================================*
 16664	 *                              stop_beep                                    *
 16665	 *===========================================================================*/
 16666	PRIVATE void stop_beep(tmrp)
 16667	timer_t *tmrp;
 16668	{
 16669	/* Отключение динамика путем сброса битов 0 и 1 в PORT_B. */
 16670	  int port_b_val;
 16671	  if (sys_inb(PORT_B, &port_b_val)==OK && 
 16672	        sys_outb(PORT_B, (port_b_val & ~3))==OK)
 16673	                beeping = FALSE;
 16674	}
	
 16676	/*===========================================================================*
 16677	 *                              scr_init                                     *
 16678	 *===========================================================================*/
 16679	PUBLIC void scr_init(tp)
 16680	tty_t *tp;
 16681	{
 16682	/* Инициализация драйвера экрана. */
 16683	  console_t *cons;
 16684	  phys_bytes vid_base;
 16685	  u16_t bios_columns, bios_crtbase, bios_fontlines;
 16686	  u8_t bios_rows;
 16687	  int line;
 16688	  int s;
 16689	  static int vdu_initialized = 0;
 16690	  unsigned page_size;
 16691	
 16692	  /* Сопоставление консоли с терминалом. */
 16693	  line = tp - &tty_table[0];
 16694	  if (line >= nr_cons) return;
 16695	  cons = &cons_table[line];
 16696	  cons->c_tty = tp;
 16697	  tp->tty_priv = cons;
 16698	
 16699	  /* Инициализация драйвера клавиатуры. */
 16700	  kb_init(tp);
 16701	
 16702	  /* Заполнение указателей на функции терминала. */
 16703	  tp->tty_devwrite = cons_write;
 16704	  tp->tty_echo = cons_echo;
 16705	  tp->tty_ioctl = cons_ioctl;
 16706	
 16707	  /* Получение параметров BIOS, описывающих монитор. */
 16708	  if (! vdu_initialized++) {
 16709	
 16710	        /* Что с проверкой ошибок? Что делать при сбое??? */
 16711	        s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_SCREEN_COLS_ADDR,
 16712	                SELF, D, (vir_bytes) &bios_columns, VDU_SCREEN_COLS_SIZE);
 16713	        s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_CRT_BASE_ADDR, 
 16714	                SELF, D, (vir_bytes) &bios_crtbase, VDU_CRT_BASE_SIZE);
 16715	        s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_SCREEN_ROWS_ADDR, 
 16716	                SELF, D, (vir_bytes) &bios_rows, VDU_SCREEN_ROWS_SIZE);
 16717	        s=sys_vircopy(SELF, BIOS_SEG, (vir_bytes) VDU_FONTLINES_ADDR, 
 16718	                SELF, D, (vir_bytes) &bios_fontlines, VDU_FONTLINES_SIZE);
 16719	
 16720	        vid_port = bios_crtbase;
 16721	        scr_width = bios_columns;
 16722	        font_lines = bios_fontlines;
 16723	        scr_lines = machine.vdu_ega ? bios_rows+1 :  25;
 16724	
 16725	        if (color) {
 16726	                vid_base = COLOR_BASE;
 16727	                vid_size = COLOR_SIZE;
 16728	        } else {
 16729	                vid_base = MONO_BASE;
 16730	                vid_size = MONO_SIZE;
 16731	        }
 16732	        if (machine.vdu_ega) vid_size = EGA_SIZE;
 16733	        wrap = ! machine.vdu_ega;
 16734	
 16735	        s = sys_segctl(&vid_index, &vid_seg, &vid_off, vid_base, vid_size);
 16736	
 16737	        vid_size >>= 1;         /* счетчик слов */
 16738	        vid_mask = vid_size - 1;
 16739	
 16740	        /* Размер экрана (число отображаемых символов.) */
 16741	        scr_size = scr_lines * scr_width;
 16742	
 16743	        /* Число консолей ограничивается только возможностями видеопамяти. */
 16744	        nr_cons = vid_size / scr_size;
 16745	        if (nr_cons > NR_CONS) nr_cons = NR_CONS;
 16746	        if (nr_cons > 1) wrap = 0;
 16747	        page_size = vid_size / nr_cons;
 16748	  }
 16749	
 16750	  cons->c_start = line * page_size;
 16751	  cons->c_limit = cons->c_start + page_size;
 16752	  cons->c_cur = cons->c_org = cons->c_start;
 16753	  cons->c_attr = cons->c_blank = BLANK_COLOR;
 16754	
 16755	  if (line != 0) {
 16756	        /* Очистка неконсольных видеотерминалов. */
 16757	        blank_color = BLANK_COLOR;
 16758	        mem_vid_copy(BLANK_MEM, cons->c_start, scr_size);
 16759	  } else {
  16760	        int i, n;
 16761	        /* Установка курсора консоли видеотерминала внизу. Позднее c_cur
 16762	         * обновится автоматически.
 16763	         */
 16764	        scroll_screen(cons, SCROLL_UP);
 16765	        cons->c_row = scr_lines - 1;
 16766	        cons->c_column = 0;
 16767	  }
 16768	  select_console(0);
 16769	  cons_ioctl(tp, 0);
 16770	}
	
 16772	/*===========================================================================*
 16773	 *                              kputc                                        *
 16774	 *===========================================================================*/
 16775	PUBLIC void kputc(c)
 16776	int c;
 16777	{
 16778	        putk(c);
 16779	}
	
 16781	/*===========================================================================*
 16782	 *                              do_new_kmess                                 *
 16783	 *===========================================================================*/
 16784	PUBLIC void do_new_kmess(m)
 16785	message *m;
 16786	{
 16787	/* Уведомление о новом сообщении ядра. */
 16788	  struct kmessages kmess;                       /* структура kmessages */
 16789	  static int prev_next = 0;                     /* предыдущий-следующий просмотренный */
 16790	  int size, next;
 16791	  int bytes;
 16792	  int r;
 16793	
 16794	  /* Попытка получить свежую копию буфера с сообщениями ядра. */
 16795	  sys_getkmessages(&kmess);
 16796	
 16797	  /* Печать только новой части. Определение числа новых байтов с помощью текущего и
 16798	   * предыдущего индексов 'next'. Обратите внимание на то, что буфер ядра циклический.
 16799	   * Это замечательно работает, если размер новых данных меньше KMESS_BUF_SIZE; иначе мы
 16800	   * теряем здесь % KMESS_BUF_SIZE.  
 16801	   * Проверка положительности размера, ведь буфер может быть пустым!
 16802	   */
 16803	  if (kmess.km_size > 0) {
 16804	      bytes = ((kmess.km_next + KMESS_BUF_SIZE) - prev_next) % KMESS_BUF_SIZE;
 16805	      r=prev_next;
 16806	      while (bytes > 0) {                       
 16807	          putk( kmess.km_buf[(r%KMESS_BUF_SIZE)] );
 16808	          bytes --;
 16809	          r ++;
 16810	      }
 16811	      putk(0);                  /* завершение для сброса вывода */
 16812	  }
 16813	
 16814	  /* Работа почти завершена, сохранение 'next', чтобы мы могли определить, какую часть
 16815	   * сообщений ядра напечатать в следующий раз при получении уведомления.
 16816	   */
 16817	  prev_next = kmess.km_next;
 16818	}
	
 16820	/*===========================================================================*
 16821	 *                              do_diagnostics                               *
 16822	 *===========================================================================*/
 16823	PUBLIC void do_diagnostics(m_ptr)
 16824	message *m_ptr;                 /* указатель на сообщение-запрос */
 16825	{
 16826	/* Печать строки для сервера. */
 16827	  char c;
 16828	  vir_bytes src;
 16829	  int count;
 16830	  int result = OK;
 16831	  int proc_nr = m_ptr->DIAG_PROC_NR;
 16832	  if (proc_nr == SELF) proc_nr = m_ptr->m_source;
 16833	
 16834	  src = (vir_bytes) m_ptr->DIAG_PRINT_BUF;
 16835	  for (count = m_ptr->DIAG_BUF_COUNT; count > 0; count--) {
 16836	        if (sys_vircopy(proc_nr, D, src++, SELF, D, (vir_bytes) &c, 1) != OK) {
 16837	                result = EFAULT;
 16838	                break;
 16839	        }
 16840	        putk(c);
 16841	  }
 16842	  putk(0);                      /* Всегда завершать, даже с EFAULT */
 16843	  m_ptr->m_type = result;
 16844	  send(m_ptr->m_source, m_ptr);
 16845	}
	
 16847	/*===========================================================================*
 16848	 *                              putk                                         *
 16849	 *===========================================================================*/
 16850	PRIVATE void putk(c)
 16851	int c;                          /* символ для печати */
 16852	{
 16853	/* Эта процедура используется версией функции printf(), связанной с драйвером терминала.
 16854	 * Библиотечная версия посылает сообщение файловой системе, которая не подходит для
 16855	 * печати внутри терминала. Эта версия просто помещает символ в очередь и начинает
 16856	 * вывод.
 16857	 */
 16858	  if (c != 0) {
 16859	        if (c == '\n') putk('\r');
 16860	        out_char(&cons_table[0], (int) c);
 16861	  } else {
 16862	        flush(&cons_table[0]);
 16863	  }
 16864	}
	
 16866	/*===========================================================================*
 16867	 *                              toggle_scroll                                *
 16868	 *===========================================================================*/
 16869	PUBLIC void toggle_scroll()
 16870	{
 16871	/* Переключение между аппаратной и программной прокруткой. */
 16872	
 16873	  cons_org0();
 16874	  softscroll = !softscroll;
 16875	  printf("%sware scrolling enabled.\n", softscroll ? "Soft" :  "Hard");
 16876	}
	
 16878	/*===========================================================================*
 16879	 *                              cons_stop                                    *
 16880	 *===========================================================================*/
 16881	PUBLIC void cons_stop()
 16882	{
 16883	/* Подготовка к остановке или перезагрузке системы. */
 16884	  cons_org0();
 16885	  softscroll = 1;
 16886	  select_console(0);
 16887	  cons_table[0].c_attr = cons_table[0].c_blank = BLANK_COLOR;
 16888	}
	
 16890	/*===========================================================================*
 16891	 *                              cons_org0                                    *
 16892	 *===========================================================================*/
 16893	PRIVATE void cons_org0()
 16894	{
 16895	/* Прокрутка видеопамяти назад, чтобы установить источник видео в 0. */
 16896	  int cons_line;
 16897	  console_t *cons;
 16898	  unsigned n;
 16899	
 16900	  for (cons_line = 0; cons_line < nr_cons; cons_line++) {
 16901	        cons = &cons_table[cons_line];
 16902	        while (cons->c_org > cons->c_start) {
 16903	                n = vid_size - scr_size;        /* количество неиспользованной памяти. */
 16904	                if (n > cons->c_org - cons->c_start)
 16905	                        n = cons->c_org - cons->c_start;
 16906	                vid_vid_copy(cons->c_org, cons->c_org - n, scr_size);
 16907	                cons->c_org -= n;
 16908	        }
 16909	        flush(cons);
 16910	  }
 16911	  select_console(ccurrent);
 16912	}
	
 16914	/*===========================================================================*
 16915	 *                              select_console                               *
 16916	 *===========================================================================*/
 16917	PUBLIC void select_console(int cons_line)
 16918	{
 16919	/* Установка консоли с номером 'cons_line' в качестве текущей. */
 16920	
 16921	  if (cons_line < 0 || cons_line >= nr_cons) return;
 16922	  ccurrent = cons_line;
 16923	  curcons = &cons_table[cons_line];
 16924	  set_6845(VID_ORG, curcons->c_org);
 16925	  set_6845(CURSOR, curcons->c_cur);
 16926	}
	
 16928	/*===========================================================================*
 16929	 *                              con_loadfont                                 *
 16930	 *===========================================================================*/
 16931	PUBLIC int con_loadfont(m)
 16932	message *m;
 16933	{
 16934	/* Загрузка шрифта в EGA- или VGA-адаптер. */
 16935	  int result;
 16936	  static struct sequence seq1[7] = {
 16937	        { GA_SEQUENCER_INDEX, 0x00, 0x01 },
 16938	        { GA_SEQUENCER_INDEX, 0x02, 0x04 },
 16939	        { GA_SEQUENCER_INDEX, 0x04, 0x07 },
 16940	        { GA_SEQUENCER_INDEX, 0x00, 0x03 },
 16941	        { GA_GRAPHICS_INDEX, 0x04, 0x02 },
 16942	        { GA_GRAPHICS_INDEX, 0x05, 0x00 },
 16943	        { GA_GRAPHICS_INDEX, 0x06, 0x00 },
 16944	  };
 16946	        { GA_SEQUENCER_INDEX, 0x00, 0x01 },
 16947	        { GA_SEQUENCER_INDEX, 0x02, 0x03 },
 16948	        { GA_SEQUENCER_INDEX, 0x04, 0x03 },
 16949	        { GA_SEQUENCER_INDEX, 0x00, 0x03 },
 16950	        { GA_GRAPHICS_INDEX, 0x04, 0x00 },
 16951	        { GA_GRAPHICS_INDEX, 0x05, 0x10 },
 16952	        { GA_GRAPHICS_INDEX, 0x06,    0 },
 16953	  };
 16954	
 16955	  seq2[6].value= color ? 0x0E :  0x0A;
 16956	
 16957	  if (!machine.vdu_ega) return(ENOTTY);
 16958	  result = ga_program(seq1);    /* отображение памяти шрифта */
 16959	
 16960	  result = sys_physcopy(m->PROC_NR, D, (vir_bytes) m->ADDRESS, 
 16961	        NONE, PHYS_SEG, (phys_bytes) GA_VIDEO_ADDRESS, (phys_bytes)GA_FONT_SIZE);
 16962	
 16963	  result = ga_program(seq2);    /* восстановление */
 16964	
 16965	  return(result);
 16966	}
	
 16968	/*===========================================================================*
 16969	 *                              ga_program                                   *
 16970	 *===========================================================================*/
 16971	PRIVATE int ga_program(seq)
 16972	struct sequence *seq;
 16973	{
 16974	  pvb_pair_t char_out[14];
 16975	  int i;
 16976	  for (i=0; i<7; i++) {
 16977	      pv_set(char_out[2*i], seq->index, seq->port);
 16978	      pv_set(char_out[2*i+1], seq->index+1, seq->value);
 16979	      seq++;
 16980	  } 
 16981	  return sys_voutb(char_out, 14);
 16982	}
	
 16984	/*===========================================================================*
 16985	 *                              cons_ioctl                                   *
 16986	 *===========================================================================*/
 16987	PRIVATE int cons_ioctl(tp, try)
 16988	tty_t *tp;
 16989	int try;
 16990	{
 16991	/* Установка размеров экрана. */
 16992	
 16993	  tp->tty_winsize.ws_row= scr_lines;
 16994	  tp->tty_winsize.ws_col= scr_width;
 16995	  tp->tty_winsize.ws_xpixel= scr_width * 8;
 16996	  tp->tty_winsize.ws_ypixel= scr_lines * font_lines;
 16997	}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/pm.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 17000	/* Это главный заголовочный файл менеджера процессов. Он включает некоторые другие файлы
 17001	 * и определяет основные константы.
 17002	 */
 17003	#define _POSIX_SOURCE      1    /* заголовочные файлы должны включать содержимое для POSIX */
 17004	#define _MINIX             1    /* заголовочные файлы должны включать содержимое для MINIX */
 17005	#define _SYSTEM            1    /* указание заголовочным файлам на то, что это ядро */
 17006	
 17007	/* Следующие заголовочные файлы включаются в файлы *.c автоматически. */
 17008	#include <minix/config.h>       /* ДОЛЖЕН быть первым */
 17009	#include <ansi.h>               /* ДОЛЖЕН быть вторым */
 17010	#include <sys/types.h>
 17011	#include <minix/const.h>
 17012	#include <minix/type.h>
 17013	
 17014	#include <fcntl.h>
 17015	#include <unistd.h>
 17016	#include <minix/syslib.h>
 17017	#include <minix/sysutil.h>
 17018	
 17019	#include <limits.h>
 17020	#include <errno.h>
 17021	
 17022	#include "const.h"
 17023	#include "type.h"
 17024	#include "proto.h"
 17025	#include "glo.h"





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/const.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 17100	/* Константы, используемые менеджером процессов. */
 17101	
 17102	#define NO_MEM ((phys_clicks) 0)  /* возвращается alloc_mem() при отсутствии памяти */
 17103	
 17104	#define NR_PIDS        30000    /* идентификаторы процессов лежат в диапазоне от 0 до NR_PIDS-1.
 17105	                                 * (магическая константа: некоторые устаревшие приложения
 17106	                                 * используют 'short' вместо pid_t.)
 17107	                                 */
 17108	
 17109	#define PM_PID             0    /* идентификатор процесса менеджера процессов */
 17110	#define INIT_PID           1    /* идентификатор процесса INIT */
 17111	

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/type.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 17200	/* Если бы менеджер процессов использовал внутренние типы данных, их определения
 17201	 * были бы размещены в этом файле. Этот файл включен только из соображений аналогии 
 17202	 * с ядром и файловой системой, которые используют локальные типы данных.
 17203	 */
 17204	

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/proto.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 17300	/* Прототипы функций. */
 17301	
 17302	struct mproc;
 17303	struct stat;
 17304	struct mem_map;
 17305	struct memory;
 17306	
 17307	#include <timers.h>
 17308	
 17309	/* alloc.c */
 17310	_PROTOTYPE( phys_clicks alloc_mem, (phys_clicks clicks)                 );
 17311	_PROTOTYPE( void free_mem, (phys_clicks base, phys_clicks clicks)       );
 17312	_PROTOTYPE( void mem_init, (struct memory *chunks, phys_clicks *free)   );
 17313	#define swap_in()                       ((void)0)
 17314	#define swap_inqueue(rmp)               ((void)0)
 17315	
 17316	/* break.c */
 17317	_PROTOTYPE( int adjust, (struct mproc *rmp,
 17318	                        vir_clicks data_clicks, vir_bytes sp)           );
 17319	_PROTOTYPE( int do_brk, (void)                                          );
 17320	_PROTOTYPE( int size_ok, (int file_type, vir_clicks tc, vir_clicks dc,
 17321	                        vir_clicks sc, vir_clicks dvir, vir_clicks s_vir) );
 17322	
 17323	/* devio.c */
 17324	_PROTOTYPE( int do_dev_io, (void) );
 17325	_PROTOTYPE( int do_dev_io, (void) );
 17326	
 17327	/* dmp.c */
 17328	_PROTOTYPE( int do_fkey_pressed, (void)                                         );
 17329	
 17330	/* exec.c */
 17331	_PROTOTYPE( int do_exec, (void)                                         );
 17332	_PROTOTYPE( void rw_seg, (int rw, int fd, int proc, int seg,
 17333	                                                phys_bytes seg_bytes)   );
 17334	_PROTOTYPE( struct mproc *find_share, (struct mproc *mp_ign, Ino_t ino,
 17335	                        Dev_t dev, time_t ctime)                        );
 17336	
 17337	/* forkexit.c */
 17338	_PROTOTYPE( int do_fork, (void)                                         );
 17339	_PROTOTYPE( int do_pm_exit, (void)                                      );
 17340	_PROTOTYPE( int do_waitpid, (void)                                      );
 17341	_PROTOTYPE( void pm_exit, (struct mproc *rmp, int exit_status)          );
 17342	
 17343	/* getset.c */
 17344	_PROTOTYPE( int do_getset, (void)                                       );
 17345	
 17346	/* main.c */
 17347	_PROTOTYPE( int main, (void)                                            );
 17348	
 17349	/* misc.c */
 17350	_PROTOTYPE( int do_reboot, (void)                                       );
 17351	_PROTOTYPE( int do_getsysinfo, (void)                                   );
 17352	_PROTOTYPE( int do_getprocnr, (void)                                    );
 17353	_PROTOTYPE( int do_svrctl, (void)                                       );
 17354	_PROTOTYPE( int do_allocmem, (void)                                     );
 17355	_PROTOTYPE( int do_freemem, (void)                                      );
 17356	_PROTOTYPE( int do_getsetpriority, (void)                               );
 17357	
 17358	_PROTOTYPE( void setreply, (int proc_nr, int result)                    );
 17359	
 17360	/* signal.c */
 17361	_PROTOTYPE( int do_alarm, (void)                                        );
 17362	_PROTOTYPE( int do_kill, (void)                                         );
 17363	_PROTOTYPE( int ksig_pending, (void)                                    );
 17364	_PROTOTYPE( int do_pause, (void)                                        );
 17365	_PROTOTYPE( int set_alarm, (int proc_nr, int sec)                       );
 17366	_PROTOTYPE( int check_sig, (pid_t proc_id, int signo)                   );
 17367	_PROTOTYPE( void sig_proc, (struct mproc *rmp, int sig_nr)              );
 17368	_PROTOTYPE( int do_sigaction, (void)                                    );
 17369	_PROTOTYPE( int do_sigpending, (void)                                   );
 17370	_PROTOTYPE( int do_sigprocmask, (void)                                  );
 17371	_PROTOTYPE( int do_sigreturn, (void)                                    );
 17372	_PROTOTYPE( int do_sigsuspend, (void)                                   );
 17373	_PROTOTYPE( void check_pending, (struct mproc *rmp)                     );
 17374	
 17375	/* time.c */
 17376	_PROTOTYPE( int do_stime, (void)                                        );
 17377	_PROTOTYPE( int do_time, (void)                                         );
 17378	_PROTOTYPE( int do_times, (void)                                        );
 17379	_PROTOTYPE( int do_gettimeofday, (void)                                 );
 17380	
 17381	/* timers.c */
 17382	_PROTOTYPE( void pm_set_timer, (timer_t *tp, int delta, 
 17383	        tmr_func_t watchdog, int arg));
 17384	_PROTOTYPE( void pm_expire_timers, (clock_t now));
 17385	_PROTOTYPE( void pm_cancel_timer, (timer_t *tp));
 17386	
 17387	/* trace.c */
 17388	_PROTOTYPE( int do_trace, (void)                                        );
 17389	_PROTOTYPE( void stop_proc, (struct mproc *rmp, int sig_nr)             );
 17390	
 17391	/* utility.c */
 17392	_PROTOTYPE( pid_t get_free_pid, (void)                                  );
 17393	_PROTOTYPE( int allowed, (char *name_buf, struct stat *s_buf, int mask) );
 17394	_PROTOTYPE( int no_sys, (void)                                          );
 17395	_PROTOTYPE( void panic, (char *who, char *mess, int num)                );
 17396	_PROTOTYPE( void tell_fs, (int what, int p1, int p2, int p3)            );
 17397	_PROTOTYPE( int get_stack_ptr, (int proc_nr, vir_bytes *sp)             );
 17398	_PROTOTYPE( int get_mem_map, (int proc_nr, struct mem_map *mem_map)     );
 17399	_PROTOTYPE( char *find_param, (const char *key));
 17400	_PROTOTYPE( int proc_from_pid, (pid_t p));

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/glo.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 17500	/* EXTERN определяется как внешнее везде, исключая файл table.c */
 17501	#ifdef _TABLE
 17502	#undef EXTERN
 17503	#define EXTERN
 17504	#endif
 17505	
 17506	/* Глобальные переменные. */
 17507	EXTERN struct mproc *mp;        /* указатель на запись 'mproc' текущего процесса */
 17508	EXTERN int procs_in_use;        /* число процессов, помеченных как IN_USE */
 17509	EXTERN char monitor_params[128*sizeof(char *)]; /* параметры загрузочного монитора */
 17510	EXTERN struct kinfo kinfo;                      /* информация ядра */
 17511	
 17512	/* Параметры вызова. */
 17513	EXTERN message m_in;            /* входящее сообщение. */
 17514	EXTERN int who;                 /* номер вызывающего процесса */
 17515	EXTERN int call_nr;             /* номер системного вызова */
 17516	
 17517	extern _PROTOTYPE (int (*call_vec[]), (void) ); /* обработчики системных вызовов */
 17518	extern char core_name[];        /* имя файла, в котором создаются образы памяти */
 17519	EXTERN sigset_t core_sset;      /* сигналы, вызывающие образы памяти */
 17520	EXTERN sigset_t ign_sset;       /* сигналы, игнорируемые по умолчанию */
 17521	




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/mproc.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 17600	/* Эта таблица содержит по одной записи на процесс. Она содержит всю информацию
 17601	 * по управлению процессами. В ней определены различные данные, в том числе
 17602	 * сегменты кода, данных и стека, uid, gid и различные флаги.  Ядро и файловая
 17603	 * система также имеют таблицы процессов, содержащих информацию о конкретных
 17604	 * процессах.
 17605	 */
 17606	#include <timers.h>
 17607	
 17608	EXTERN struct mproc {
 17609	  struct mem_map mp_seg[NR_LOCAL_SEGS]; /* указывает на код, данные и стек */
 17610	  char mp_exitstatus;           /* хранит состояние процесса, когда он завершается */
 17611	  char mp_sigstatus;            /* хранит номер сигнала уничтоженного процесса */
 17612	  pid_t mp_pid;                 /* идентификатор процесса */
 17613	  pid_t mp_procgrp;             /* pid группы процессов (используется для сигналов) */
 17614	  pid_t mp_wpid;                /* pid процесса, которого ожидает этот процесс */
 17615	  int mp_parent;                /* индекс родительского процесса */
 17616	
 17617	  /* Пользовательское и системное время дочернего процесса, учитываемое при его завершении. */
 17618	  clock_t mp_child_utime;       /* суммарное пользовательское время дочерних процессов */
 17619	  clock_t mp_child_stime;       /* суммарное системное время дочерних процессов */
 17620	
 17621	  /* Реальные и эффективные значения uid и gid. */
 17622	  uid_t mp_realuid;             /* реальное значение uid процесса */
 17623	  uid_t mp_effuid;              /* эффективное значение uid процесса */
 17624	  gid_t mp_realgid;             /* реальное значение gid процесса */
 17625	  gid_t mp_effgid;              /* эффективное значение gid процесса */
 17626	
 17627	  /* Идентификационные данные файла. */
 17628	  ino_t mp_ino;                 /* номер индексного узла файла */
 17629	  dev_t mp_dev;                 /* номер устройства файловой системы */
 17630	  time_t mp_ctime;              /* время изменения индексного узла */
 17631	
 17632	  /* Информация об обработке сигналов. */
 17633	  sigset_t mp_ignore;           /* 1 означает игнорировать сигнал, 0 - не игнорировать */
 17634	  sigset_t mp_catch;            /* 1 означает перехватывать сигнал, 0 - не перехватывать */
 17635	  sigset_t mp_sig2mess;         /* 1 означает преобразовывать в уведомление */
 17636	  sigset_t mp_sigmask;          /* блокируемые сигналы */
 17637	  sigset_t mp_sigmask2;         /* сохраненная копия mp_sigmask */
 17638	  sigset_t mp_sigpending;       /* активные сигналы, требующие обработки */
 17639	  struct sigaction mp_sigact[_NSIG + 1]; /* как в sigaction(2) */
 17640	  vir_bytes mp_sigreturn;       /* адрес функции __sigreturn из C-библиотеки */
 17641	  struct timer mp_timer;        /* сторожевой таймер для alarm(2) */
 17642	
 17643	  /* Обратная совместимость для сигналов. */
 17644	  sighandler_t mp_func;         /* все сигналы собраны в единый пользовательский fcn */
 17645	
 17646	  unsigned mp_flags;            /* биты флагов */
 17647	  vir_bytes mp_procargs;        /* указатель на начальные аргументы стека процесса */
 17648	  struct mproc *mp_swapq;       /* очередь процессов, ожидающих подкачки */
 17649	  message mp_reply;             /* ответное сообщение */
 17650	
 17651	  /* Приоритет планирования. */
 17652	  signed int mp_nice;           /* PRIO_MIN..PRIO_MAX, обычно 0. */
 17653	
 17654	  char mp_name[PROC_NAME_LEN];  /* имя процесса */
 17655	} mproc[NR_PROCS];
 17656	
 17657	/* Значения флагов */
 17658	#define IN_USE          0x001   /* устанавливается, когда запись 'mproc' используется */
 17659	#define WAITING         0x002   /* устанавливается системным вызовом WAIT */
 17660	#define ZOMBIE          0x004   /* устанавливается EXIT, очищается WAIT */
 17661	#define PAUSED          0x008   /* устанавливается системным вызовом PAUSE */
 17662	#define ALARM_ON        0x010   /* устанавливается при запуске таймера SIGALRM */
 17663	#define SEPARATE        0x020   /* устанавливается, если у файла разделены код и данные */
 17664	#define TRACED          0x040   /* устанавливается, если процесс подлежит трассировке */
 17665	#define STOPPED         0x080   /* устанавливается, если процесс остановлен для трассировки */
 17666	#define SIGSUSPENDED    0x100   /* устанавливается системным вызовом SIGSUSPEND */
 17667	#define REPLY           0x200   /* устанавливается при ожидающем ответном сообщении */
 17668	#define ONSWAP          0x400   /* устанавливается, если сегмент данных вытеснен */
 17669	#define SWAPIN          0x800   /* устанавливается при помещении в очередь подкачки */
 17670	#define DONT_SWAP      0x1000   /* никогда не вытеснять этот процесс */
 17671	#define PRIV_PROC      0x2000   /* системный процесс с особыми привилегиями */
 17672	
 17673	#define NIL_MPROC ((struct mproc *) 0)
 17674	

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/param.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 17700	/* Следующие имена являются синонимами для переменных во входном сообщении. */
 17701	#define addr            m1_p1
 17702	#define exec_name       m1_p1
 17703	#define exec_len        m1_i1
 17704	#define func            m6_f1
 17705	#define grp_id          m1_i1
 17706	#define namelen         m1_i2
 17707	#define pid             m1_i1
 17708	#define procnr          m1_i1
 17709	#define seconds         m1_i1
 17710	#define sig             m6_i1
 17711	#define stack_bytes     m1_i2
 17712	#define stack_ptr       m1_p2
 17713	#define status          m1_i1
 17714	#define usr_id          m1_i1
 17715	#define request         m2_i2
 17716	#define taddr           m2_l1
 17717	#define data            m2_l2
 17718	#define sig_nr          m1_i2
 17719	#define sig_nsa         m1_p1
 17720	#define sig_osa         m1_p2
 17721	#define sig_ret         m1_p3
 17722	#define sig_set         m2_l1
 17723	#define sig_how         m2_i1
 17724	#define sig_flags       m2_i2
 17725	#define sig_context     m2_p1
 17726	#define info_what       m1_i1
 17727	#define info_where      m1_p1
 17728	#define reboot_flag     m1_i1
 17729	#define reboot_code     m1_p1
 17730	#define reboot_strlen   m1_i2
 17731	#define svrctl_req      m2_i1
 17732	#define svrctl_argp     m2_p1
 17733	#define stime           m2_l1
 17734	#define memsize         m4_l1
 17735	#define membase         m4_l2
 17736	
 17737	/* Следующие имена являются синонимами переменных в ответном сообщении. */
 17738	#define reply_res       m_type
 17739	#define reply_res2      m2_i1
 17740	#define reply_ptr       m2_p1
 17741	#define reply_mask      m2_l1   
 17742	#define reply_trace     m2_l2   
 17743	#define reply_time      m2_l1
 17744	#define reply_utime     m2_l2
 17745	#define reply_t1        m4_l1
 17746	#define reply_t2        m4_l2
 17747	#define reply_t3        m4_l3
 17748	#define reply_t4        m4_l4
 17749	#define reply_t5        m4_l5
 17750	
 17751	/* Следующие имена используются для информирования файловой системы об определенных событиях. */
 17752	#define tell_fs_arg1    m1_i1
 17753	#define tell_fs_arg2    m1_i2
 17754	#define tell_fs_arg3    m1_i3
 17755	

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/table.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 17800	/* Этот файл содержит таблицу, используемую для сопоставления номеров системных вызовов и
 17801	 * обслуживающих их процедур.
 17802	 */
 17803	
 17804	#define _TABLE
 17805	
 17806	#include "pm.h"
 17807	#include <minix/callnr.h>
 17808	#include <signal.h>
 17809	#include "mproc.h"
 17810	#include "param.h"
 17811	
 17812	/* Разное */
 17813	char core_name[] = "core";      /* имя файла, в котором создаются образы памяти. */
 17814	
 17815	_PROTOTYPE (int (*call_vec[NCALLS]), (void) ) = {
 17816	        no_sys,         /*  0 = не используется  */
 17817	        do_pm_exit,     /*  1 = exit    */
 17818	        do_fork,        /*  2 = fork    */
 17819	        no_sys,         /*  3 = read    */
 17820	        no_sys,         /*  4 = write   */
 17821	        no_sys,         /*  5 = open    */
 17822	        no_sys,         /*  6 = close   */
 17823	        do_waitpid,     /*  7 = wait    */
 17824	        no_sys,         /*  8 = creat   */
 17825	        no_sys,         /*  9 = link    */
 17826	        no_sys,         /* 10 = unlink  */
 17827	        do_waitpid,     /* 11 = waitpid */
 17828	        no_sys,         /* 12 = chdir   */
 17829	        do_time,        /* 13 = time    */
 17830	        no_sys,         /* 14 = mknod   */
 17831	        no_sys,         /* 15 = chmod   */
 17832	        no_sys,         /* 16 = chown   */
 17833	        do_brk,         /* 17 = break   */
 17834	        no_sys,         /* 18 = stat    */
 17835	        no_sys,         /* 19 = lseek   */
 17836	        do_getset,      /* 20 = getpid  */
 17837	        no_sys,         /* 21 = mount   */
 17838	        no_sys,         /* 22 = umount  */
 17839	        do_getset,      /* 23 = setuid  */
 17840	        do_getset,      /* 24 = getuid  */
 17841	        do_stime,       /* 25 = stime   */
 17842	        do_trace,       /* 26 = ptrace  */
 17843	        do_alarm,       /* 27 = alarm   */
 17844	        no_sys,         /* 28 = fstat   */
 17845	        do_pause,       /* 29 = pause   */
 17846	        no_sys,         /* 30 = utime   */
 17847	        no_sys,         /* 31 = (stty)  */
 17848	        no_sys,         /* 32 = (gtty)  */
 17849	        no_sys,         /* 33 = access  */
 17850	        no_sys,         /* 34 = (nice)  */
 17851	        no_sys,         /* 35 = (ftime) */
 17852	        no_sys,         /* 36 = sync    */
 17853	        do_kill,        /* 37 = kill    */
 17854	        no_sys,         /* 38 = rename  */
 17855	        no_sys,         /* 39 = mkdir   */
 17856	        no_sys,         /* 40 = rmdir   */
 17857	        no_sys,         /* 41 = dup     */
 17858	        no_sys,         /* 42 = pipe    */
 17859	        do_times,       /* 43 = times   */
 17860	        no_sys,         /* 44 = (prof)  */
 17861	        no_sys,         /* 45 = unused  */
 17862	        do_getset,      /* 46 = setgid  */
 17863	        do_getset,      /* 47 = getgid  */
 17864	        no_sys,         /* 48 = (signal)*/
 17865	        no_sys,         /* 49 = unused  */
 17866	        no_sys,         /* 50 = unused  */
 17867	        no_sys,         /* 51 = (acct)  */
 17868	        no_sys,         /* 52 = (phys)  */
 17869	        no_sys,         /* 53 = (lock)  */
 17870	        no_sys,         /* 54 = ioctl   */
 17871	        no_sys,         /* 55 = fcntl   */
 17872	        no_sys,         /* 56 = (mpx)   */
 17873	        no_sys,         /* 57 = unused  */
 17874	        no_sys,         /* 58 = unused  */
 17875	        do_exec,        /* 59 = execve  */
 17876	        no_sys,         /* 60 = umask   */
 17877	        no_sys,         /* 61 = chroot  */
 17878	        do_getset,      /* 62 = setsid  */
 17879	        do_getset,      /* 63 = getpgrp */
 17880	
 17881	        no_sys,         /* 64 = unused */
 17882	        no_sys,         /* 65 = UNPAUSE */
 17883	        no_sys,         /* 66 = unused  */
 17884	        no_sys,         /* 67 = REVIVE  */
 17885	        no_sys,         /* 68 = TASK_REPLY  */
 17886	        no_sys,         /* 69 = unused  */
 17887	        no_sys,         /* 70 = unused  */
 17888	        do_sigaction,   /* 71 = sigaction   */
 17889	        do_sigsuspend,  /* 72 = sigsuspend  */
 17890	        do_sigpending,  /* 73 = sigpending  */
 17891	        do_sigprocmask, /* 74 = sigprocmask */
 17892	        do_sigreturn,   /* 75 = sigreturn   */
 17893	        do_reboot,      /* 76 = reboot  */
 17894	        do_svrctl,      /* 77 = svrctl  */
 17895	
 17896	        no_sys,         /* 78 = unused */
 17897	        do_getsysinfo,  /* 79 = getsysinfo */
 17898	        do_getprocnr,   /* 80 = getprocnr */
 17899	        no_sys,         /* 81 = unused */
 17900	        no_sys,         /* 82 = fstatfs */
 17901	        do_allocmem,    /* 83 = memalloc */
 17902	        do_freemem,     /* 84 = memfree */
 17903	        no_sys,         /* 85 = select */
 17904	        no_sys,         /* 86 = fchdir */
 17905	        no_sys,         /* 87 = fsync */
 17906	        do_getsetpriority,      /* 88 = getpriority */
 17907	        do_getsetpriority,      /* 89 = setpriority */
 17908	        do_time,        /* 90 = gettimeofday */
 17909	};
 17910	/* Здесь не должна возникать ошибка, связанная с отрицательным размером массива:  */
 17911	extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 :  -1];

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/main.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 18000	/* Этот файл содержит основную программу менеджера процессов и несколько связанных с ней
 18001	 * процедур. Когда MINIX начинает работу, ядро инициализирует себя и свои задания, а затем
 18002	 * запускает менеджер процессов и файловую систему. Они инициализируют себя максимально
 18003	 * быстро. Менеджер процессов запрашивает у ядра всю свободную память и начинает 
 18004	 * обслуживать запросы.
 18005	 *
 18006	 * Точки входа в этот файл: 
 18007	 *   main:       запускает менеджер процессов
 18008	 *   setreply:   отправляет ответ процессу, обратившемуся к менеджеру процессов с системным вызовом
 18009	 */
 18010	
 18011	#include "pm.h"
 18012	#include <minix/keymap.h>
 18013	#include <minix/callnr.h>
 18014	#include <minix/com.h>
 18015	#include <signal.h>
 18016	#include <stdlib.h>
 18017	#include <fcntl.h>
 18018	#include <sys/resource.h>
 18019	#include <string.h>
 18020	#include "mproc.h"
 18021	#include "param.h"
 18022	
 18023	#include "../../kernel/const.h"
 18024	#include "../../kernel/config.h"
 18025	#include "../../kernel/type.h"
 18026	#include "../../kernel/proc.h"
 18027	
 18028	FORWARD _PROTOTYPE( void get_work, (void)                               );
 18029	FORWARD _PROTOTYPE( void pm_init, (void)                                );
 18030	FORWARD _PROTOTYPE( int get_nice_value, (int queue)                     );
 18031	FORWARD _PROTOTYPE( void get_mem_chunks, (struct memory *mem_chunks)    );
 18032	FORWARD _PROTOTYPE( void patch_mem_chunks, (struct memory *mem_chunks, 
 18033	        struct mem_map *map_ptr)        );
 18034	
 18035	#define click_to_round_k(n) \
 18036	        ((unsigned) ((((unsigned long) (n) << CLICK_SHIFT) + 512) / 1024))
 18037	
 18038	/*===========================================================================*
 18039	 *                              main                                         *
 18040	 *===========================================================================*/
 18041	PUBLIC int main()
 18042	{
 18043	/* Главная процедура менеджера процессов. */
 18044	  int result, s, proc_nr;
 18045	  struct mproc *rmp;
 18046	  sigset_t sigset;
 18047	
 18048	  pm_init();                    /* инициализация таблиц менеджера процессов */
 18049	
 18050	  /* главный бесконечный цикл менеджера процессов, получающий и выполняющий работу */
 18051	  while (TRUE) {
 18052	        get_work();             /* ожидание системного вызова менеджера процессов */
 18053	
 18054	        /* Проверка системных уведомлений. Рассмотрение особых случаев. */
 18055	        if (call_nr == SYN_ALARM) {
 18056	                pm_expire_timers(m_in.NOTIFY_TIMESTAMP);
 18057	                result = SUSPEND;               /* не отвечать */
 18058	        } else if (call_nr == SYS_SIG) {        /* активные сигналы */
 18059	                sigset = m_in.NOTIFY_ARG;
 18060	                if (sigismember(&sigset, SIGKSIG))  (void) ksig_pending();
 18061	                result = SUSPEND;               /* не отвечать */
 18062	        }
 18063	        /* Иначе, если номер системного вызова является допустимым, его обслуживание. */
 18064	        else if ((unsigned) call_nr >= NCALLS) {
 18065	                result = ENOSYS;
 18066	        } else {
 18067	                result = (*call_vec[call_nr])();
 18068	        }
 18069	
 18070	        /* Передача результатов пользователю, указывающая на завершение вызова.*/
 18071	        if (result != SUSPEND) setreply(who, result);
 18072	
 18073	        swap_in();              /* возможно, процесс может быть вытеснен? */
 18074	
 18075	        /* Передача всех активных ответных сообщений, в том числе ответ на вызов,
 18076	         * обработанный ранее. Процессы не должны вытесняться.
 18077	         */
 18078	        for (proc_nr=0, rmp=mproc; proc_nr < NR_PROCS; proc_nr++, rmp++) {
 18079	                /* Тем временем процесс может быть уничтожен сигналом (например,
 18080	                 * если сигнал, уничтожающий процесс, был разблокирован) без ведома
 18081	                 * менеджера процессов. Если запись больше не используется или является
 18082	                 * зомби, не пытаться послать ответ.
 18083	                 */
 18084	                if ((rmp->mp_flags & (REPLY | ONSWAP | IN_USE | ZOMBIE)) ==
 18085	                   (REPLY | IN_USE)) {
 18086	                        if ((s=send(proc_nr, &rmp->mp_reply)) != OK) {
 18087	                                panic(__FILE__,"PM can't reply to", proc_nr);
 18088	                        }
 18089	                        rmp->mp_flags &= ~REPLY;
 18090	                }
 18091	        }
 18092	  }
 18093	  return(OK);
 18094	}
	
 18096	/*===========================================================================*
 18097	 *                              get_work                                     *
 18098	 *===========================================================================*/
 18099	PRIVATE void get_work()
 18100	{
 18101	/* Ожидание следующего сообщения и извлечение из него полезной информации */
 18102	  if (receive(ANY, &m_in) != OK) panic(__FILE__,"PM receive error", NO_NUM);
 18103	  who = m_in.m_source;          /* источник сообщения */
 18104	  call_nr = m_in.m_type;        /* номер системного вызова */
 18105	
 18106	  /* Запись процесса, совершившего вызов. Если вызов послан ядром, не использовать
 18107	   * собственную запись менеджера процессов. Это может произойти в случае синхронного
 18108	   * оповещения (источник CLOCK) или активного сигнала ядра (источник SYSTEM).
 18109	   */
 18110	  mp = &mproc[who < 0 ? PM_PROC_NR :  who];
 18111	}
	
 18113	/*===========================================================================*
 18114	 *                              setreply                                     *
 18115	 *===========================================================================*/
 18116	PUBLIC void setreply(proc_nr, result)
 18117	int proc_nr;                    /* процесс, которому нужно ответить */
 18118	int result;                     /* результат вызова (обычно OK или номер ошибки) */
 18119	{
 18120	/* Составление ответного сообщение, которое будет отправлено пользовательскому процессу
 18121	 * позднее. Системные вызовы иногда могут заполнять другие поля, этот код лишь для главного
 18122	 * возвращаемого значения и установки флага обязательной отправки ответа.
 18123	 */
 18124	  register struct mproc *rmp = &mproc[proc_nr];
 18125	
 18126	  rmp->mp_reply.reply_res = result;
 18127	  rmp->mp_flags |= REPLY;       /* активный ответ */
 18128	
 18129	  if (rmp->mp_flags & ONSWAP)
 18130	        swap_inqueue(rmp);      /* нужно вернуть этот вытесненный процесс назад */
 18131	}
	
 18133	/*===========================================================================*
 18134	 *                              pm_init                                      *
 18135	 *===========================================================================*/
 18136	PRIVATE void pm_init()
 18137	{
 18138	/* Инициализация менеджера процессов. 
 18139	 * Информация об использовании памяти собирается из монитора загрузки, ядра и всех
 18140	 * процессов, находящихся в образе системы. Изначально эта информация помещается в
 18141	 * массив mem_chunks. Элементы mem_chunks - структуры memory, содержащие базовые
 18142	 * адреса и размеры в кликах. В массиве не может быть более 8 элементов. После
 18143	 * формирования массива его содержимое используется для инициализации списка
 18144	 * свободных участков. Место для этого списка зарезервировано в виде массива,
 18145	 * количество элементов которого в 2 раза больше максимального числа процессов.
 18146	 * Список является связанным, а его элементы, структуры hole, кроме базовых
 18147	 * адресов и размеров в кликах, также содержат место для связи – указателя 
 18148	 * на следующий элемент.
 18149	*/
 18150	  int s;
 18151	  static struct boot_image image[NR_BOOT_PROCS];
 18152	  register struct boot_image *ip;
 18153	  static char core_sigs[] = { SIGQUIT, SIGILL, SIGTRAP, SIGABRT,
 18154	                        SIGEMT, SIGFPE, SIGUSR1, SIGSEGV, SIGUSR2 };
 18155	  static char ign_sigs[] = { SIGCHLD };
 18156	  register struct mproc *rmp;
 18157	  register char *sig_ptr;
 18158	  phys_clicks total_clicks, minix_clicks, free_clicks;
 18159	  message mess;
 18160	  struct mem_map mem_map[NR_LOCAL_SEGS];
 18161	  struct memory mem_chunks[NR_MEMS];
 18162	
 18163	  /* Инициализация таблицы процессов, включая таймеры. */
 18164	  for (rmp=&mproc[0]; rmp<&mproc[NR_PROCS]; rmp++) {
 18165	        tmr_inittimer(&rmp->mp_timer);
 18166	  }
 18167	
 18168	  /* Создание набора сигналов, создающих дампы, и набора сигналов, игнорируемых
 18169	   * по умолчанию.
 18170	   */
 18171	  sigemptyset(&core_sset);
 18172	  for (sig_ptr = core_sigs; sig_ptr < core_sigs+sizeof(core_sigs); sig_ptr++)
 18173	        sigaddset(&core_sset, *sig_ptr);
 18174	  sigemptyset(&ign_sset);
 18175	  for (sig_ptr = ign_sigs; sig_ptr < ign_sigs+sizeof(ign_sigs); sig_ptr++)
 18176	        sigaddset(&ign_sset, *sig_ptr);
 18177	
 18178	  /* Получение копии параметров монитора загрузки и структуры информации о ядре.  
 18179	   * Разбор списка свободных участков памяти. Этот список создан монитором загрузки, 
 18180	   * однако его необходимо скорректировать для ядра и системных процессов.
 18181	   */
 18182	  if ((s=sys_getmonparams(monitor_params, sizeof(monitor_params))) != OK)
 18183	      panic(__FILE__,"get monitor params failed",s);
 18184	  get_mem_chunks(mem_chunks);
 18185	  if ((s=sys_getkinfo(&kinfo)) != OK)
 18186	      panic(__FILE__,"get kernel info failed",s);
 18187	
 18188	  /* Получение карты памяти ядра, чтобы определить объем используемой им памяти. */
 18189	  if ((s=get_mem_map(SYSTASK, mem_map)) != OK)
 18190	        panic(__FILE__,"couldn't get memory map of SYSTASK",s);
 18191	  minix_clicks = (mem_map[S].mem_phys+mem_map[S].mem_len)-mem_map[T].mem_phys;
 18192	  patch_mem_chunks(mem_chunks, mem_map);
 18193	
 18194	  /* Инициализация таблицы процессов менеджера процессов. Запрос копии таблицы образа
 18195	   * системы, которая определена на уровне ядра, чтобы определить, какие записи заполнять.
 18196	   */
 18197	  if (OK != (s=sys_getimage(image))) 
 18198	        panic(__FILE__,"couldn't get image table:  %d\n", s);
 18199	  procs_in_use = 0;                             /* начало заполнения таблицы */
 18200	  printf("Building process table: ");           /* демонстрация того, что происходит */
 18201	  for (ip = &image[0]; ip < &image[NR_BOOT_PROCS]; ip++) {              
 18202	        if (ip->proc_nr >= 0) {                 /* у заданий отрицательные номера */
 18203	                procs_in_use += 1;              /* найден пользовательский процесс */
 18204	
 18205	                /* Задать параметры процесса, полученные из таблицы образа. */
 18206	                rmp = &mproc[ip->proc_nr];      
 18207	                strncpy(rmp->mp_name, ip->proc_name, PROC_NAME_LEN); 
 18208	                rmp->mp_parent = RS_PROC_NR;
 18209	                rmp->mp_nice = get_nice_value(ip->priority);
 18210	                if (ip->proc_nr == INIT_PROC_NR) {      /* пользовательский процесс */
 18211	                        rmp->mp_pid = INIT_PID;
 18212	                        rmp->mp_flags |= IN_USE; 
 18213	                        sigemptyset(&rmp->mp_ignore);   
 18214	                }
 18215	                else {                                  /* системный процесс */
 18216	                        rmp->mp_pid = get_free_pid();
 18217	                        rmp->mp_flags |= IN_USE | DONT_SWAP | PRIV_PROC; 
 18218	                        sigfillset(&rmp->mp_ignore);    
 18219	                }
 18220	                sigemptyset(&rmp->mp_sigmask);
 18221	                sigemptyset(&rmp->mp_catch);
 18222	                sigemptyset(&rmp->mp_sig2mess);
 18223	
 18224	                /* Получение карты памяти для этого процесса из ядра. */
 18225	                if ((s=get_mem_map(ip->proc_nr, rmp->mp_seg)) != OK)
 18226	                        panic(__FILE__,"couldn't get process entry",s);
 18227	                if (rmp->mp_seg[T].mem_len != 0) rmp->mp_flags |= SEPARATE;
 18228	                minix_clicks += rmp->mp_seg[S].mem_phys + 
 18229	                        rmp->mp_seg[S].mem_len - rmp->mp_seg[T].mem_phys;
 18230	                patch_mem_chunks(mem_chunks, rmp->mp_seg);
 18231	
 18232	                /* Информирование файловой системы об этом процессе. */
 18233	                mess.PR_PROC_NR = ip->proc_nr;
 18234	                mess.PR_PID = rmp->mp_pid;
 18235	                if (OK != (s=send(FS_PROC_NR, &mess)))
 18236	                        panic(__FILE__,"can't sync up with FS", s);
 18237	                printf(" %s", ip->proc_name);   /* вывод имени процесса */
 18238	        }
 18239	  }
 18240	  printf(".\n");                                /* последний процесс обработан */
 18241	
 18242	  /* Изменение некоторых параметров. Менеджер процессов имеет особенности. */
 18243	  mproc[PM_PROC_NR].mp_pid = PM_PID;            /* магическое значение pid */
 18244	  mproc[PM_PROC_NR].mp_parent = PM_PROC_NR;     /* у менеджера процессов нет родителя */
 18245	
 18246	  /* Информирование файловой системы о том, что системных процессов больше нет, и синхронизация. */
 18247	  mess.PR_PROC_NR = NONE;
 18248	  if (sendrec(FS_PROC_NR, &mess) != OK || mess.m_type != OK)
 18249	        panic(__FILE__,"can't sync up with FS", NO_NUM);
 18250	
 18251	  /* Инициализация таблиц и отображение информации по всей физической памяти. */
 18252	  printf("Physical memory: ");
 18253	  mem_init(mem_chunks, &free_clicks);
 18254	  total_clicks = minix_clicks + free_clicks;
 18255	  printf(" total %u KB,", click_to_round_k(total_clicks));
 18256	  printf(" system %u KB,", click_to_round_k(minix_clicks));
 18257	  printf(" free %u KB.\n", click_to_round_k(free_clicks));
 18258	}
	
 18260	/*===========================================================================*
 18261	 *                              get_nice_value                               *
 18262	 *===========================================================================*/
 18263	PRIVATE int get_nice_value(queue)
 18264	int queue;                              /* здесь хранятся области памяти */
 18265	{
 18266	/* Процессам в загрузочном образе назначены приоритеты. Менеджер процессов не знает о
 18267	 * приоритетах, но вместо них использует уровни 'вежливости'. Приоритет – число в диапазоне
 18268	 * от MIN_USER_Q до MAX_USER_Q. Мы должны перевести приоритеты в диапазон от PRIO_MIN до PRIO_MAX.
 18269	 */ 
 18270	  int nice_val = (queue - USER_Q) * (PRIO_MAX-PRIO_MIN+1) / 
 18271	      (MIN_USER_Q-MAX_USER_Q+1);
 18272	  if (nice_val > PRIO_MAX) nice_val = PRIO_MAX; /* не должно произойти */
 18273	  if (nice_val < PRIO_MIN) nice_val = PRIO_MIN; /* не должно произойти */
 18274	  return nice_val;
 18275	}
	
 18277	/*===========================================================================*
 18278	 *                              get_mem_chunks                               *
 18279	 *===========================================================================*/
 18280	PRIVATE void get_mem_chunks(mem_chunks)
 18281	struct memory *mem_chunks;                      /* здесь хранятся области памяти */
 18282	{
 18283	/* Инициализация списка свободной памяти из переменной загрузки 'memory'. Преобразование
 18284	 * байтовых смещений и размеров в этом списке в клики с надлежащим округлением. Кроме того,
 18285	 * нужно гарантировать, что не будет превышено максимальное адресное пространство систем
 18286	 * 286 или 8086, то есть в 16-разрядном защищенном режиме или в реальном режиме.
 18287	 */
 18288	  long base, size, limit;
 18289	  char *s, *end;                        /* используется для разбора переменных загрузки */ 
 18290	  int i, done = 0;
 18291	  struct memory *memp;
 18292	
 18293	  /* Инициализация нулями. */
 18294	  for (i = 0; i < NR_MEMS; i++) {
 18295	        memp = &mem_chunks[i];          /* Здесь хранится следующая область памяти */
 18296	        memp->base = memp->size = 0;
 18297	  }
 18298	  
 18299	  /* Доступная память определяется загрузчиком MINIX в виде списка пар (базовый адрес: размер)
 18300	   * в файле boothead.s. Загрузочная переменная 'memory' определена в boot.s. Формат имеет
 18301	   * вид "b0: s0,b1: s1,b2: s2", где b0: s0 - нижняя область памяти, b1: s1 - память между
 18302	   * 1M и 16M, а b2: s2 - память выше 16M. Пары b1: s1 и b2: s2 объединяются, если память
 18303	   * смежная. 
 18304	   */
 18305	  s = find_param("memory");             /* получение переменной memory */
 18306	  for (i = 0; i < NR_MEMS && !done; i++) {
 18307	        memp = &mem_chunks[i];          /* здесь хранится следующий участок памяти */
 18308	        base = size = 0;                /* инициализация следующей пары (базовый адрес: размер) */
 18309	        if (*s != 0) {                  /* получение свежих данных, если не конец */     
 18310	
 18311	            /* Чтение свежего базового адреса, следующим символом ожидается двоеточие. */ 
 18312	            base = strtoul(s, &end, 0x10);              /* получение числа */
 18313	            if (end != s && *end == ': ') s = ++end;    /* пропуск ': ' */ 
 18314	            else *s=0;                  /* завершение, не должно происходить */
 18315	
 18316	            /* Чтение свежего размена, следующим символом ожидается запятая или точка в конце. */ 
 18317	            size = strtoul(s, &end, 0x10);              /* получение числа */
 18318	            if (end != s && *end == ',') s = ++end;     /* пропуск ',' */
 18319	            else done = 1;
 18320	        }
 18321	        limit = base + size;    
 18322	        base = (base + CLICK_SIZE-1) & ~(long)(CLICK_SIZE-1);
 18323	        limit &= ~(long)(CLICK_SIZE-1);
 18324	        if (limit <= base) continue;
 18325	        memp->base = base >> CLICK_SHIFT;
 18326	        memp->size = (limit - base) >> CLICK_SHIFT;
 18327	  }
 18328	}
	
 18330	/*===========================================================================*
 18331	 *                              patch_mem_chunks                             *
 18332	 *===========================================================================*/
 18333	PRIVATE void patch_mem_chunks(mem_chunks, map_ptr)
 18334	struct memory *mem_chunks;                      /* здесь хранятся участки памяти */
 18335	struct mem_map *map_ptr;                        /* удаляемая память */
 18336	{
 18337	/* Удаление памяти сервера из списка свободных участков. Монитор загрузки обещает
 18338	 * помещать процессы в начало участков памяти. Все задания используют одинаковый 
 18339	 * базовый адрес, поэтому только первое задание изменяет список свободных участков.
 18340	 * Серверы и процесс init имеют собственные пространства памяти, и их память будет
 18341	 * удалена из списка. 
 18342	 */
 18343	  struct memory *memp;
 18344	  for (memp = mem_chunks; memp < &mem_chunks[NR_MEMS]; memp++) {
 18345	        if (memp->base == map_ptr[T].mem_phys) {
 18346	                memp->base += map_ptr[T].mem_len + map_ptr[D].mem_len;
 18347	                memp->size -= map_ptr[T].mem_len + map_ptr[D].mem_len;
 18348	        }
 18349	  }
 18350	}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/forkexit.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 18400	/* Этот файл работает над созданием процессов (посредством FORK) и их удалением (посредством
 18401	 * EXIT/WAIT). Когда создается новый процесс, в таблице 'mproc' для него выделяется новая
 18402	 * запись, и родительский образ памяти копируется в образ памяти дочернего процесса. После
 18403	 * этого о новом процессе информируются ядро и файловая система. Удаление процесса из
 18404	 * таблицы 'mproc' происходит в двух случаях (1) процесс завершил работу или был уничтожен
 18405	 * сигналом (2) родительский процесс выполнил вызов WAIT. Если процесс сам завершает
 18406	 * работу, он продолжает занимать запись до тех пор, пока родитель не вызовет WAIT.
 18407	 *
 18408	 * Этот файл имеет следующие точки входа: 
 18409	 *   do_fork:     выполнение системного вызова FORK
 18410	 *   do_pm_exit:  выполнение системного вызова EXIT (обращение к функции pm_exit())
 18411	 *   pm_exit:     фактическое завершение процесса
 18412	 *   do_wait:     выполнение системного вызова WAITPID или WAIT
 18413	 */
 18414	
 18415	#include "pm.h"
 18416	#include <sys/wait.h>
 18417	#include <minix/callnr.h>
 18418	#include <minix/com.h>
 18419	#include <signal.h>
 18420	#include "mproc.h"
 18421	#include "param.h"
 18422	
 18423	#define LAST_FEW            2   /* несколько последних записей зарезервировано для суперпользователя */
 18424	
 18425	FORWARD _PROTOTYPE (void cleanup, (register struct mproc *child) );
 18426	
 18427	/*===========================================================================*
 18428	 *                              do_fork                                      *
 18429	 *===========================================================================*/
 18430	PUBLIC int do_fork()
 18431	{
 18432	/* Процесс, на который указывает указатель 'mp', создал новый процесс. Создание дочернего процесса. */
 18433	  register struct mproc *rmp;   /* указатель на родительский процесс */
 18434	  register struct mproc *rmc;   /* указатель на дочерний процесс */
 18435	  int child_nr, s;
 18436	  phys_clicks prog_clicks, child_base;
 18437	  phys_bytes prog_bytes, parent_abs, child_abs; /* только Intel */
 18438	  pid_t new_pid;
 18439	
 18440	 /* Если таблицы окажутся полными при вызове FORK, ничего не начинать, поскольку
 18441	  * восстановление посередине процесса весьма проблематично.
 18442	  */
 18443	  rmp = mp;
 18444	  if ((procs_in_use == NR_PROCS) || 
 18445	                (procs_in_use >= NR_PROCS-LAST_FEW && rmp->mp_effuid != 0))
 18446	  {
 18447	        printf("PM:  warning, process table is full!\n");
 18448	        return(EAGAIN);
 18449	  }
 18450	
 18451	  /* Определение объема памяти, который следует выделить. Копировать нужно только данные и  
 18452	   * стек, поскольку сегмент кода либо используется совместно, либо имеет нулевую длину.
 18453	   */
 18454	  prog_clicks = (phys_clicks) rmp->mp_seg[S].mem_len;
 18455	  prog_clicks += (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
 18456	  prog_bytes = (phys_bytes) prog_clicks << CLICK_SHIFT;
 18457	  if ( (child_base = alloc_mem(prog_clicks)) == NO_MEM) return(ENOMEM);
 18458	
 18459	  /* Создание копии образа памяти родителя для дочернего процесса. */
 18460	  child_abs = (phys_bytes) child_base << CLICK_SHIFT;
 18461	  parent_abs = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT;
 18462	  s = sys_abscopy(parent_abs, child_abs, prog_bytes);
 18463	  if (s < 0) panic(__FILE__,"do_fork can't copy", s);
 18464	
 18465	  /* Поиск записи для дочернего процесса в mproc.  Запись должна существовать. */
 18466	  for (rmc = &mproc[0]; rmc < &mproc[NR_PROCS]; rmc++)
 18467	        if ( (rmc->mp_flags & IN_USE) == 0) break;
 18468	
 18469	  /* Настройка дочернего процесса и его карты памяти; копирование карты родителя в запись в таблице mproc. */
 18470	  child_nr = (int)(rmc - mproc);        /* номер записи дочернего процесса */
 18471	  procs_in_use++;
 18472	  *rmc = *rmp;         /* копирование записи родительского процесса в запись дочернего процесса */
 18473	  rmc->mp_parent = who;                 /* регистрация родителя дочернего процесса */
 18474	  /* наследуются только эти флаги */
 18475	  rmc->mp_flags &= (IN_USE|SEPARATE|PRIV_PROC|DONT_SWAP);
 18476	  rmc->mp_child_utime = 0;              /* сброс администрирования */
 18477	  rmc->mp_child_stime = 0;              /* сброс администрирования */
 18478	
 18479	  /* Дочерний процесс с разделенными данными и кодом хранит сегмент кода родителя. 
 18480	   * Сегменты данных и стека должны принадлежать новой копии.
 18481	   */
 18482	  if (!(rmc->mp_flags & SEPARATE)) rmc->mp_seg[T].mem_phys = child_base;
 18483	  rmc->mp_seg[D].mem_phys = child_base;
 18484	  rmc->mp_seg[S].mem_phys = rmc->mp_seg[D].mem_phys + 
 18485	                        (rmp->mp_seg[S].mem_vir - rmp->mp_seg[D].mem_vir);
 18486	  rmc->mp_exitstatus = 0;
 18487	  rmc->mp_sigstatus = 0;
 18488	
 18489	  /* Поиск свободного значения pid для дочернего процесса и запись его в таблицу. */
 18490	  new_pid = get_free_pid();
 18491	  rmc->mp_pid = new_pid;        /* назначение pid дочернему процессу */
 18492	
 18493	  /* Информирование ядра и файловой системы о (теперь уже успешном) вызове FORK. */
 18494	  sys_fork(who, child_nr);
 18495	  tell_fs(FORK, who, child_nr, rmc->mp_pid);
 18496	
 18497	  /* Передача карты памяти дочернего процесса ядру. */
 18498	  sys_newmap(child_nr, rmc->mp_seg);
 18499	
 18500	  /* Ответ дочернему процессу, чтобы активизировать его. */
 18501	  setreply(child_nr, 0);                /* только родительский процесс получает параметры */
 18502	  rmp->mp_reply.procnr = child_nr;      /* номер дочернего процесса */
 18503	  return(new_pid);                      /* pid дочернего процесса */
 18504	}
	
 18506	/*===========================================================================*
 18507	 *                              do_pm_exit                                   *
 18508	 *===========================================================================*/
 18509	PUBLIC int do_pm_exit()
 18510	{
 18511	/* Выполнение системного вызова exit(status). Фактическая работа делается функцией
 18512	 * pm_exit(), которая также вызывается, когда процесс уничтожается сигналом.
 18513	 */
 18514	  pm_exit(mp, m_in.status);
 18515	  return(SUSPEND);              /* уничтоженный процесс не способен к общению */
 18516	}
	
 18518	/*===========================================================================*
 18519	 *                              pm_exit                                      *
 18520	 *===========================================================================*/
 18521	PUBLIC void pm_exit(rmp, exit_status)
 18522	register struct mproc *rmp;     /* указатель на завершаемый процесс */
 18523	int exit_status;                /* состояние завершения процесса (для родителя) */
 18524	{
 18525	/* Процесс закончил работу. Освобождение большей части принадлежащих ему ресурсов. Если
 18526	 * родитель процесса ждет, то освободить остальное, в противном случае сохранить запись
 18527	 * процесса и сделать его зомби.
 18528	 */
 18529	  register int proc_nr;
 18530	  int parent_waiting, right_child;
 18531	  pid_t pidarg, procgrp;
 18532	  struct mproc *p_mp;
 18533	  clock_t t[5];
 18534	
 18535	  proc_nr = (int) (rmp - mproc);        /* получение номера записи процесса */
 18536	
 18537	  /* Запомнить группу лидера сеанса. */
 18538	  procgrp = (rmp->mp_pid == mp->mp_procgrp) ? mp->mp_procgrp :  0;
 18539	
 18540	  /* Если завершившийся процесс имеет активный таймер, уничтожить его. */
 18541	  if (rmp->mp_flags & ALARM_ON) set_alarm(proc_nr, (unsigned) 0);
 18542	
 18543	  /* Учет: определить время использования и начислить его родителю. */
 18544	  sys_times(proc_nr, t);
 18545	  p_mp = &mproc[rmp->mp_parent];                        /* родитель */
 18546	  p_mp->mp_child_utime += t[0] + rmp->mp_child_utime;   /* начислить пользовательское время */
 18547	  p_mp->mp_child_stime += t[1] + rmp->mp_child_stime;   /* начислить системное время */
 18548	
 18549	  /* Информировать ядро и файловую систему о том, что процесс больше не может выполняться. */
 18550	  tell_fs(EXIT, proc_nr, 0, 0);  /* файловая система может освободить запись процесса */
 18551	  sys_exit(proc_nr);
 18552	
 18553	  /* Активные ответные сообщения для уничтоженного процесса не могут быть доставлены. */
 18554	  rmp->mp_flags &= ~REPLY;
 18555	  
 18556	  /* Освобождение памяти, занятой дочерним процессом. */
 18557	  if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, rmp->mp_ctime) == NULL) {
 18558	        /* Другие процессы не используют сегмент кода, поэтому его следует освободить. */
 18559	        free_mem(rmp->mp_seg[T].mem_phys, rmp->mp_seg[T].mem_len);
 18560	  }
 18561	  /* Освободить сегменты данных и стека. */
 18562	  free_mem(rmp->mp_seg[D].mem_phys,
 18563	      rmp->mp_seg[S].mem_vir 
 18564	        + rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
 18565	
 18566	  /* Запись процесса может быть освобождена только если родитель совершил вызов WAIT. */
 18567	  rmp->mp_exitstatus = (char) exit_status;
 18568	
 18569	  pidarg = p_mp->mp_wpid;               /* кого ждем? */
 18570	  parent_waiting = p_mp->mp_flags & WAITING;
 18571	  right_child =            /* соответствует ли дочерний процесс одному из трех условий? */
 18572	        (pidarg == -1 || pidarg == rmp->mp_pid || -pidarg == rmp->mp_procgrp);
 18573	
 18574	  if (parent_waiting && right_child) {
 18575	        cleanup(rmp);      /* информирование родителя и освобождение записи дочернего процесса */
 18576	  } else {
 18577	        rmp->mp_flags = IN_USE|ZOMBIE;  /* родитель не ждет, превратить дочерний процесс в зомби */
 18578	        sig_proc(p_mp, SIGCHLD);        /* послать родителю сигнал об уничтожении потомка */
 18579	  }
 18580	
 18581	  /* Если процесс имеет потомков, лишить их наследства. INIT - их новый родитель. */
 18582	  for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
 18583	        if (rmp->mp_flags & IN_USE && rmp->mp_parent == proc_nr) {
 18584	                /* теперь 'rmp' указывает на дочерний процесс, который нужно лишить наследства. */
 18585	                rmp->mp_parent = INIT_PROC_NR;
 18586	                parent_waiting = mproc[INIT_PROC_NR].mp_flags & WAITING;
 18587	                if (parent_waiting && (rmp->mp_flags & ZOMBIE)) cleanup(rmp);
 18588	        }
 18589	  }
 18590	
 18591	  /* Послать hangup группе, в которой процесс был лидером сеанса (если был). */
 18592	  if (procgrp != 0) check_sig(-procgrp, SIGHUP);
 18593	}
	
 18595	/*===========================================================================*
 18596	 *                              do_waitpid                                   *
 18597	 *===========================================================================*/
 18598	PUBLIC int do_waitpid()
 18599	{
 18600	/* Процесс собирается дождаться завершения дочернего процесса. Если дочерний процесс уже 
 18601	 * ждет, очистить его и завершить этот вызов WAIT. В противном случае - действительно 
 18602	 * ждать. 
 18603	 * Процесс, вызывающий WAIT, никогда не получает ответ обычным способом в конце главного
 18604	 * цикла (если только WNOHANG не установлен или дочернего процесса не существует).
 18605	 * Если дочерний процесс уже завершил работу, функция cleanup() посылает ответ, чтобы
 18606	 * разбудить родителя.
 18607	 * Этот код обрабатывает два системных вызова - WAIT и WAITPID.
 18608	 */
 18609	  register struct mproc *rp;
 18610	  int pidarg, options, children;
 18611	
 18612	  /* Задание внутренних переменных в зависимости от вызова - WAIT или WAITPID. */
 18613	  pidarg  = (call_nr == WAIT ? -1 :  m_in.pid);     /* первый параметр waitpid */
 18614	  options = (call_nr == WAIT ?  0 :  m_in.sig_nr);  /* третий параметр waitpid */
 18615	  if (pidarg == 0) pidarg = -mp->mp_procgrp;    /* pidarg < 0 ==> группа процесса */
 18616	
 18617	  /* имеется ли дочерний процесс, ожидающий, чтобы его подобрали? Сейчас pidarg != 0: 
 18618	   *    pidarg  >  0 означает, что pidarg - это pid процесса, который нужно ждать
 18619	   *    pidarg == -1 означает ожидание любого дочернего процесса
 18620	   *    pidarg  < -1 означает ожидание любого дочернего процесса, чья группа = -pidarg
 18621	   */
 18622	  children = 0;
 18623	  for (rp = &mproc[0]; rp < &mproc[NR_PROCS]; rp++) {
 18624	        if ( (rp->mp_flags & IN_USE) && rp->mp_parent == who) {
 18625	                /* Значение pidarg задает, какие дочерние процессы являются определяющими. */
 18626	                if (pidarg  > 0 && pidarg != rp->mp_pid) continue;
 18627	                if (pidarg < -1 && -pidarg != rp->mp_procgrp) continue;
 18628	
 18629	                children++;             /* этот процесс подходит */
 18630	                if (rp->mp_flags & ZOMBIE) {
 18631	                        /* Этот дочерний процесс подходит по pid и завершил работу. */
 18632	                        cleanup(rp);    /* этот дочерний процесс уже завершил работу */
 18633	                        return(SUSPEND);
 18634	                }
 18635	                if ((rp->mp_flags & STOPPED) && rp->mp_sigstatus) {
 18636	                        /* Этот дочерний процесс подходит по pid и трассируется.*/
 18637	                        mp->mp_reply.reply_res2 = 0177|(rp->mp_sigstatus << 8);
 18638	                        rp->mp_sigstatus = 0;
 18639	                        return(rp->mp_pid);
 18640	                }
 18641	        }
 18642	  }
 18643	
 18644	  /* Ни один определяющий дочерний процесс не завершил работу. Дождаться, пока кто-нибудь завершит работу, если потомки существуют. */
 18645	  if (children > 0) {
 18646	        /* Хотя бы один дочерний процесс подходит по pid, но ни один не завершил работу. */
 18647	        if (options & WNOHANG) return(0);    /* родитель не собирается ждать */
 18648	        mp->mp_flags |= WAITING;             /* родитель собирается ждать */
 18649	        mp->mp_wpid = (pid_t) pidarg;        /* сохранить pid на будущее */
 18650	        return(SUSPEND);                     /* не отвечать, дать возможность подождать */
 18651	  } else {
 18652	        /* Ни один дочерний процесс не подходит по pid. Немедленно вернуть ошибку. */
 18653	        return(ECHILD);                      /* у "родителя" нет потомков */
 18654	  }
 18655	}
	
 18657	/*===========================================================================*
 18658	 *                              cleanup                                      *
 18659	 *===========================================================================*/
 18660	PRIVATE void cleanup(child)
 18661	register struct mproc *child;   /* указывает, какой процесс завершает работу */
 18662	{
 18663	/* Закончить завершение процесса. Процесс завершил работу или был уничтожен сигналом,
 18664	 * и его родитель ждет.
 18665	 */
 18666	  struct mproc *parent = &mproc[child->mp_parent];
 18667	  int exitstatus;
 18668	
 18669	  /* Разбудить родителя, послав ответное сообщение. */
 18670	  exitstatus = (child->mp_exitstatus << 8) | (child->mp_sigstatus & 0377);
 18671	  parent->mp_reply.reply_res2 = exitstatus;
 18672	  setreply(child->mp_parent, child->mp_pid);
 18673	  parent->mp_flags &= ~WAITING;         /* родитель больше не ждет */
 18674	
 18675	  /* Освободить запись в таблице процессов и заново инициализировать некоторые поля. */
 18676	  child->mp_pid = 0;
 18677	  child->mp_flags = 0;
 18678	  child->mp_child_utime = 0;
 18679	  child->mp_child_stime = 0;
 18680	  procs_in_use--;
 18681	}
	



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/exec.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 18700	/* Этот файл обрабатывает системный вызов EXEC. Он выполняет рабоу следующим образом:
 18701	 *    - проверяет, позволяют ли разрешения запустить файл
 18702	 *    - считывает заголовок и извлекает размеры
 18703	 *    - считывает начальные аргументы и окружение из пользовательского пространства
 18704	 *    - выделяет память для нового процесса
 18705	 *    - копирует начальный стек из менеджера процессов
 18706	 *    - считывает сегменты кода и данных, копирует их в процесс
 18707	 *    - устанавливает биты setuid и setgid
 18708	 *    - заполняет таблицу 'mproc'
 18709	 *    - информирует ядро о вызове EXEC
 18710	 *    - сохраняет смещение по отношению к начальному значению argc (для ps)
 18711	 *
 18712	 * Этот файл имеет следующие точки входа: 
 18713	 *   do_exec:     выполнение системного вызова EXEC
 18714	 *   rw_seg:      считывание сегмента из файла или запись в файл
 18715	 *   find_share:  поиск процесса, сегмент кода которого можно использовать
 18716	 */
 18717	
 18718	#include "pm.h"
 18719	#include <sys/stat.h>
 18720	#include <minix/callnr.h>
 18721	#include <minix/com.h>
 18722	#include <a.out.h>
 18723	#include <signal.h>
 18724	#include <string.h>
 18725	#include "mproc.h"
 18726	#include "param.h"
 18727	
 18728	FORWARD _PROTOTYPE( int new_mem, (struct mproc *sh_mp, vir_bytes text_bytes,
 18729	                vir_bytes data_bytes, vir_bytes bss_bytes,
 18730	                vir_bytes stk_bytes, phys_bytes tot_bytes)              );
 18731	FORWARD _PROTOTYPE( void patch_ptr, (char stack[ARG_MAX], vir_bytes base) );
 18732	FORWARD _PROTOTYPE( int insert_arg, (char stack[ARG_MAX],
 18733	                vir_bytes *stk_bytes, char *arg, int replace)           );
 18734	FORWARD _PROTOTYPE( char *patch_stack, (int fd, char stack[ARG_MAX],
 18735	                vir_bytes *stk_bytes, char *script)                     );
 18736	FORWARD _PROTOTYPE( int read_header, (int fd, int *ft, vir_bytes *text_bytes,
 18737	                vir_bytes *data_bytes, vir_bytes *bss_bytes,
 18738	                phys_bytes *tot_bytes, long *sym_bytes, vir_clicks sc,
 18739	                vir_bytes *pc)                                          );
 18740	
 18741	#define ESCRIPT (-2000) /* Возвращается read_header для #! script. */
 18742	#define PTRSIZE sizeof(char *) /* Размер указателей в argv[] и envp[]. */
 18743	
 18744	/*===========================================================================*
 18745	 *                              do_exec                                      *
 18746	 *===========================================================================*/
 18747	PUBLIC int do_exec()
 18748	{
 18749	/* Выполнение вызова execve(name, argv, envp). Пользовательская библиотека создает
 18750	 * полный образ стека, в том числе указатели, аргументы, окружение и др. Стек копируется
 18751	 * в буфер внутри менеджера процессов, а затем в новый образ памяти.
 18752	 */
 18753	  register struct mproc *rmp;
 18754	  struct mproc *sh_mp;
 18755	  int m, r, fd, ft, sn;
 18756	  static char mbuf[ARG_MAX];      /* буфер для стека и нулей */
 18757	  static char name_buf[PATH_MAX]; /* имя исполняемого файла */
 18758	  char *new_sp, *name, *basename;
 18759	  vir_bytes src, dst, text_bytes, data_bytes, bss_bytes, stk_bytes, vsp;
 18760	  phys_bytes tot_bytes;         /* суммарное пространство программы, в том числе дыра */
 18761	  long sym_bytes;
 18762	  vir_clicks sc;
 18763	  struct stat s_buf[2], *s_p;
 18764	  vir_bytes pc;
 18765	
 18766	  /* Несколько проверок допустимости. */
 18767	  rmp = mp;
 18768	  stk_bytes = (vir_bytes) m_in.stack_bytes;
 18769	  if (stk_bytes > ARG_MAX) return(ENOMEM);      /* стек слишком велик */
 18770	  if (m_in.exec_len <= 0 || m_in.exec_len > PATH_MAX) return(EINVAL);
 18771	
 18772	  /* Получение имени исполняемого файла и проверка возможности исполнения. */
 18773	  src = (vir_bytes) m_in.exec_name;
 18774	  dst = (vir_bytes) name_buf;
 18775	  r = sys_datacopy(who, (vir_bytes) src,
 18776	                PM_PROC_NR, (vir_bytes) dst, (phys_bytes) m_in.exec_len);
 18777	  if (r != OK) return(r);       /* имя файла не в сегменте данных пользователя. */
 18778	
 18779	  /* Копирование стека от пользователя перед уничтожением старого образа памяти. */
 18780	  src = (vir_bytes) m_in.stack_ptr;
 18781	  dst = (vir_bytes) mbuf;
 18782	  r = sys_datacopy(who, (vir_bytes) src,
 18783	                        PM_PROC_NR, (vir_bytes) dst, (phys_bytes)stk_bytes);
 18784	  /* невозможно получить стек (например, из-за некорректного виртуального адреса) */
 18785	  if (r != OK) return(EACCES);  
 18786	
 18787	  r = 0;        /* r = 0 (первая попытка) или 1 (интерпретируемый сценарий) */
 18788	  name = name_buf;      /* имя исполняемого файла. */
 18789	  do {
 18790	        s_p = &s_buf[r];
 18791	        tell_fs(CHDIR, who, FALSE, 0);  /* переключение в окружение файловой системы пользователя */
 18792	        fd = allowed(name, s_p, X_BIT); /* является ли файл исполняемым? */
 18793	        if (fd < 0)  return(fd);                /* файл не был исполняемым */
 18794	
 18795	        /* считывание заголовка файла и извлечение размеров сегментов. */
 18796	        sc = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
 18797	
 18798	        m = read_header(fd, &ft, &text_bytes, &data_bytes, &bss_bytes, 
 18799	                                        &tot_bytes, &sym_bytes, sc, &pc);
 18800	        if (m != ESCRIPT || ++r > 1) break;
 18801	  } while ((name = patch_stack(fd, mbuf, &stk_bytes, name_buf)) != NULL);
 18802	
 18803	  if (m < 0) {
 18804	        close(fd);              /* заголовок некорректен */
 18805	        return(stk_bytes > ARG_MAX ? ENOMEM :  ENOEXEC);
 18806	  }
 18807	
 18808	  /* Может ли код другого процесса использоваться в качестве кода для этого процесса? */
 18809	  sh_mp = find_share(rmp, s_p->st_ino, s_p->st_dev, s_p->st_ctime);
 18810	
 18811	  /* Выделение новой памяти и освобождение старой. Создание карты и информирование ядра. */
 18812	  r = new_mem(sh_mp, text_bytes, data_bytes, bss_bytes, stk_bytes, tot_bytes);
 18813	  if (r != OK) {
 18814	        close(fd);              /* недостаточно памяти или программа слишком велика */
 18815	        return(r);
 18816	  }
 18817	
 18818	  /* Сохранить идентификацию файла, чтобы обеспечить возможность его совместного использования. */
 18819	  rmp->mp_ino = s_p->st_ino;
 18820	  rmp->mp_dev = s_p->st_dev;
 18821	  rmp->mp_ctime = s_p->st_ctime;
 18822	
 18823	  /* настройка стека и его копирование из менеджера процессов в новый образ памяти. */
 18824	  vsp = (vir_bytes) rmp->mp_seg[S].mem_vir << CLICK_SHIFT;
 18825	  vsp += (vir_bytes) rmp->mp_seg[S].mem_len << CLICK_SHIFT;
 18826	  vsp -= stk_bytes;
 18827	  patch_ptr(mbuf, vsp);
 18828	  src = (vir_bytes) mbuf;
 18829	  r = sys_datacopy(PM_PROC_NR, (vir_bytes) src,
 18830	                        who, (vir_bytes) vsp, (phys_bytes)stk_bytes);
 18831	  if (r != OK) panic(__FILE__,"do_exec stack copy err on", who);
 18832	
 18833	  /* чтение сегментов кода и данных */
 18834	  if (sh_mp != NULL) {
 18835	        lseek(fd, (off_t) text_bytes, SEEK_CUR);  /* сегмент кода используется совместно: пропустить */
 18836	  } else {
 18837	        rw_seg(0, fd, who, T, text_bytes);
 18838	  }
 18839	  rw_seg(0, fd, who, D, data_bytes);
 18840	
 18841	  close(fd);                    /* больше не нужно исполнять файл */
 18842	
 18843	  /* Позаботиться о битах setuid/setgid */
 18844	  if ((rmp->mp_flags & TRACED) == 0) { /* подавить при трассировке */
 18845	        if (s_buf[0].st_mode & I_SET_UID_BIT) {
 18846	                rmp->mp_effuid = s_buf[0].st_uid;
 18847	                tell_fs(SETUID,who, (int)rmp->mp_realuid, (int)rmp->mp_effuid);
 18848	        }
 18849	        if (s_buf[0].st_mode & I_SET_GID_BIT) {
 18850	                rmp->mp_effgid = s_buf[0].st_gid;
 18851	                tell_fs(SETGID,who, (int)rmp->mp_realgid, (int)rmp->mp_effgid);
 18852	        }
 18853	  }
 18854	
 18855	  /* Сохранение смещения по отношению к начальному argc (для ps) */
 18856	  rmp->mp_procargs = vsp;
 18857	
 18858	  /* Заполнение полей 'mproc', информирование ядра о завершении exec, сброс перехваченных сигналов. */
 18859	  for (sn = 1; sn <= _NSIG; sn++) {
 18860	        if (sigismember(&rmp->mp_catch, sn)) {
 18861	                sigdelset(&rmp->mp_catch, sn);
 18862	                rmp->mp_sigact[sn].sa_handler = SIG_DFL;
 18863	                sigemptyset(&rmp->mp_sigact[sn].sa_mask);
 18864	        }
 18865	  }
 18866	
 18867	  rmp->mp_flags &= ~SEPARATE;   /* выключение бита SEPARATE */
 18868	  rmp->mp_flags |= ft;          /* включение этого бита для файлов  I & D */
 18869	  new_sp = (char *) vsp;
 18870	
 18871	  tell_fs(EXEC, who, 0, 0);     /* позволить файловой системе обрабатывать файлы FD_CLOEXEC */
 18872	
 18873	  /* Система сохранит командную строку для отладки, вывода ps(1) и т. д. */
 18874	  basename = strrchr(name, '/');
 18875	  if (basename == NULL) basename = name; else basename++;
 18876	  strncpy(rmp->mp_name, basename, PROC_NAME_LEN-1);
 18877	  rmp->mp_name[PROC_NAME_LEN] = '\0';
 18878	  sys_exec(who, new_sp, basename, pc);
 18879	
 18880	  /* отправка сигнала, если процесс трассируется. */
 18881	  if (rmp->mp_flags & TRACED) check_sig(rmp->mp_pid, SIGTRAP);
 18882	
 18883	  return(SUSPEND);              /* без ответа, просто запуск новой программы */
 18884	}
	
 18886	/*===========================================================================*
 18887	 *                              read_header                                  *
 18888	 *===========================================================================*/
 18889	PRIVATE int read_header(fd, ft, text_bytes, data_bytes, bss_bytes, 
 18890	                                                tot_bytes, sym_bytes, sc, pc)
 18891	int fd;                         /* дескриптор для считывания исполняемого файла */
 18892	int *ft;                        /* для возврата ft-номера */
 18893	vir_bytes *text_bytes;          /* для возврата размера кода */
 18894	vir_bytes *data_bytes;          /* для возврата размера инициализированных данных */
 18895	vir_bytes *bss_bytes;           /* для возврата размера bss */
 18896	phys_bytes *tot_bytes;          /* для возвратаn общего размера */
 18897	long *sym_bytes;                /* для возврата размера таблицы символов */
 18898	vir_clicks sc;                  /* размер стека в кликах */
 18899	vir_bytes *pc;                  /* точка входа в программу */
 18900	{
 18901	/* Считывание заголовка и извлечение размеров кода, данных, bss и суммарного размера. */
 18902	
 18903	  int m, ct;
 18904	  vir_clicks tc, dc, s_vir, dvir;
 18905	  phys_clicks totc;
 18906	  struct exec hdr;              /* сюда считывается заголовок a.out */
 18907	
 18908	  /* Считывание заголовка и проверка магического числа. Стандартный заголовок MINIX 
 18909	   * определен в <a.out.h>. Он включает 8 символов и 6 значений типа long.
 18910	   * За ними следуют еще 4 значения long, не используемые здесь.
 18911	   *    Байт 0:  магическое число 0x01
 18912	   *    Байт 1:  магическое число 0x03
 18913	   *    Байт 2:  нормальный = 0x10 (не проверяется, 0 - OK), раздельные I/D = 0x20
 18914	   *    Байт 3:  Тип процессора, Intel 16 бит = 0x04, Intel 32 бита = 0x10, 
 18915	   *            Motorola = 0x0B, Sun SPARC = 0x17
 18916	   *    Байт 4:  Длина заголовка = 0x20
 18917	   *    Байты 5-7 не используются.
 18918	   *
 18919	   *    Еще 6 значений long:
 18920	   *    Байты 8-11:   размер сегментов кода в байтах
 18921	   *    Байты 12-15:  размер сегмента инициализированных данных в байтах
 18922	   *    Байты 16-19:  размер bss в байтах
 18923	   *    Байты 20-23:  точка входа в программу
 18924	   *    Байты 24-27:  суммарная память, выделенная программе (код, данные и стек)
 18925	   *    Байты 28-31:  размер таблицы символов в байтах
 18926	   * Значения long представлены в машинно-зависимом порядке, в прямом порядке на 8088,
 18927	   * в обратном порядке на 68000.
 18928	   * Сразу после заголовка следуют сегменты кода и данных, и таблица символов (если есть). 
 18929	   * Размеры указаны в заголовке. Вызов exec копирует в память только сегменты кода и 
 18930	   * данных. Заголовок используется только здесь. Таблица символов предназначена для
 18931	   * отладчика и игнорируется здесь. 
 18932	   *
 18933	   */
 18934	
 18935	  if ((m= read(fd, &hdr, A_MINHDR)) < 2) return(ENOEXEC);
 18936	
 18937	  /* Интерпретируемый сценарий? */
 18938	  if (((char *) &hdr)[0] == '#' && ((char *) &hdr)[1] == '!') return(ESCRIPT);
 18939	
 18940	  if (m != A_MINHDR) return(ENOEXEC);
 18941	
 18942	  /* Проверка магического числа, типа процессора и флагов. */
 18943	  if (BADMAG(hdr)) return(ENOEXEC);
 18944	  if (hdr.a_cpu != A_I80386) return(ENOEXEC);
 18945	  if ((hdr.a_flags & ~(A_NSYM | A_EXEC | A_SEP)) != 0) return(ENOEXEC);
 18946	
 18947	  *ft = ( (hdr.a_flags & A_SEP) ? SEPARATE :  0);    /* раздельные I & D или нет */
 18948	
 18949	  /* Получение размеров кода и данных. */
 18950	  *text_bytes = (vir_bytes) hdr.a_text; /* размер кода в байтах */
 18951	  *data_bytes = (vir_bytes) hdr.a_data; /* размер данных в байтах */
 18952	  *bss_bytes  = (vir_bytes) hdr.a_bss;  /* размер bss в байтах */
 18953	  *tot_bytes  = hdr.a_total;            /* суммарное число байтов, выделенных программе */
 18954	  *sym_bytes  = hdr.a_syms;             /* размер таблицы символов в байтах */
 18955	  if (*tot_bytes == 0) return(ENOEXEC);
 18956	
 18957	  if (*ft != SEPARATE) {
 18958	        /* Если пространства I & D не разделены, все это считается данными. Код=0*/
 18959	        *data_bytes += *text_bytes;
 18960	        *text_bytes = 0;
 18961	  }
 18962	  *pc = hdr.a_entry;    /* Начальный адрес для выполнения */
 18963	
 18964	  /* Проверка допустимости размеров сегментов. */
 18965	  tc = ((unsigned long) *text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
 18966	  dc = (*data_bytes + *bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
 18967	  totc = (*tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
 18968	  if (dc >= totc) return(ENOEXEC);      /* стек должен быть размером как минимум 1 клик */
 18969	  dvir = (*ft == SEPARATE ? 0 :  tc);
 18970	  s_vir = dvir + (totc - sc);
 18971	  m = (dvir + dc > s_vir) ? ENOMEM :  OK;
 18972	  ct = hdr.a_hdrlen & BYTE;             /* длина заголовка */
 18973	  if (ct > A_MINHDR) lseek(fd, (off_t) ct, SEEK_SET); /* пропустить неиспользуемый заголовок */
 18974	  return(m);
 18975	}
	
 18977	/*===========================================================================*
 18978	 *                              new_mem                                      *
 18979	 *===========================================================================*/
 18980	PRIVATE int new_mem(sh_mp, text_bytes, data_bytes,
 18981	        bss_bytes,stk_bytes,tot_bytes)
 18982	struct mproc *sh_mp;            /* код можно использовать совместно с этим процессом */
 18983	vir_bytes text_bytes;           /* размер сегмента кода в байтах */
 18984	vir_bytes data_bytes;           /* размер инициализированных данных в байтах */
 18985	vir_bytes bss_bytes;            /* размер bss в байтах */
 18986	vir_bytes stk_bytes;            /* размер начального сегмента стека в байтах */
 18987	phys_bytes tot_bytes;           /* общий объем выделяемой памяти в байтах, включая дыру*/
 18988	{
 18989	/* Выделение новой памяти и освобождение старой. Изменение карты памяти и передача новой
 18990	 * карты ядру.  Обнуление bss, дыры и стека нового образа памяти.
 18991	 */
 18992	
 18993	  register struct mproc *rmp = mp;
 18994	  vir_clicks text_clicks, data_clicks, gap_clicks, stack_clicks, tot_clicks;
 18995	  phys_clicks new_base;
 18996	  phys_bytes bytes, base, bss_offset;
 18997	  int s;
 18998	
 18999	  /* Не нужно выделять память под код, если его можно использовать совместно. */
 19000	  if (sh_mp != NULL) text_bytes = 0;
 19001	
 19002	  /* Разрешить вытеснение старых данных (на самом деле, это трата времени, поскольку
 19003	   * мы все равно их удалим)
 19004	   */
 19005	  rmp->mp_flags |= WAITING;
 19006	
 19007	  /* Получение новой памяти. Каждая состоит из четырех частей: код, (данные+bss), дыра,
 19008	   * и стек. Каждая часть занимает целое число кликов и начинается на границе клика.
 19009	   * Данные и bss объединены.
 19010	   */
 19011	  text_clicks = ((unsigned long) text_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
 19012	  data_clicks = (data_bytes + bss_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
 19013	  stack_clicks = (stk_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
 19014	  tot_clicks = (tot_bytes + CLICK_SIZE - 1) >> CLICK_SHIFT;
 19015	  gap_clicks = tot_clicks - data_clicks - stack_clicks;
 19016	  if ( (int) gap_clicks < 0) return(ENOMEM);
 19017	
 19018	  /* Попытка выделения памяти под новый процесс. */
 19019	  new_base = alloc_mem(text_clicks + tot_clicks);
 19020	  if (new_base == NO_MEM) return(ENOMEM);
 19021	
 19022	  /* Мы располагаем памятью для нового образа. Удаляем старый. */
 19023	  rmp = mp;
 19024	
 19025	  if (find_share(rmp, rmp->mp_ino, rmp->mp_dev, rmp->mp_ctime) == NULL) {
 19026	        /* Ни один другой процесс не использует этот сегмент кода, освобождаем его. */
 19027	        free_mem(rmp->mp_seg[T].mem_phys, rmp->mp_seg[T].mem_len);
 19028	  }
 19029	  /* Освобождение сегментов данных и стека. */
 19030	  free_mem(rmp->mp_seg[D].mem_phys,
 19031	   rmp->mp_seg[S].mem_vir + rmp->mp_seg[S].mem_len - rmp->mp_seg[D].mem_vir);
 19032	
 19033	  /* Теперь мы прошли точку невозврата. Старый образ памяти навсегда утрачен,
 19034	   * память под новый образ выделена. Установка новой карты памяти и информирование
 19035	   * о ней.
 19036	   */
 19037	  if (sh_mp != NULL) {
 19038	        /* Совместное использование сегмента кода. */
 19039	        rmp->mp_seg[T] = sh_mp->mp_seg[T];
 19040	  } else {
 19041	        rmp->mp_seg[T].mem_phys = new_base;
 19042	        rmp->mp_seg[T].mem_vir = 0;
 19043	        rmp->mp_seg[T].mem_len = text_clicks;
 19044	  }
 19045	  rmp->mp_seg[D].mem_phys = new_base + text_clicks;
 19046	  rmp->mp_seg[D].mem_vir = 0;
 19047	  rmp->mp_seg[D].mem_len = data_clicks;
 19048	  rmp->mp_seg[S].mem_phys = rmp->mp_seg[D].mem_phys + data_clicks + gap_clicks;
 19049	  rmp->mp_seg[S].mem_vir = rmp->mp_seg[D].mem_vir + data_clicks + gap_clicks;
 19050	  rmp->mp_seg[S].mem_len = stack_clicks;
 19051	
 19052	  sys_newmap(who, rmp->mp_seg);   /* информирование ядра о новой карте */
 19053	
 19054	  /* Старая память могла быть вытеснена, но новая память реальна. */
 19055	  rmp->mp_flags &= ~(WAITING|ONSWAP|SWAPIN);
 19056	
 19057	  /* Обнуление сегмента bss, дыры и стека. */
 19058	  bytes = (phys_bytes)(data_clicks + gap_clicks + stack_clicks) << CLICK_SHIFT;
 19059	  base = (phys_bytes) rmp->mp_seg[D].mem_phys << CLICK_SHIFT;
 19060	  bss_offset = (data_bytes >> CLICK_SHIFT) << CLICK_SHIFT;
 19061	  base += bss_offset;
 19062	  bytes -= bss_offset;
 19063	
 19064	  if ((s=sys_memset(0, base, bytes)) != OK) {
 19065	        panic(__FILE__,"new_mem can't zero", s);
 19066	  }
 19067	
 19068	  return(OK);
 19069	}
	
 19071	/*===========================================================================*
 19072	 *                              patch_ptr                                    *
 19073	 *===========================================================================*/
 19074	PRIVATE void patch_ptr(stack, base)
 19075	char stack[ARG_MAX];            /* указатель на образ стека внутри менеджера процессов */
 19076	vir_bytes base;                 /* виртуальный базовый адрес стека в пространстве пользователя */
 19077	{
 19078	/* При выполнении вызова exec(name, argv, envp) пользователь создает образ стека с
 19079	 * указателями на arg и env относительно начала стека. Теперь эти указатели должны быть
 19080	 * перемещены, поскольку стек не расположен по адресу 0 в адресном пространстве
 19081	 * пользователя.
 19082	 */
 19083	
 19084	  char **ap, flag;
 19085	  vir_bytes v;
 19086	
 19087	  flag = 0;                     /* считает количество нулевых указателей */
 19088	  ap = (char **) stack;         /* изначально указывает на 'nargs' */
 19089	  ap++;                         /* теперь указывает на argv[0] */
 19090	  while (flag < 2) {
 19091	        if (ap >= (char **) &stack[ARG_MAX]) return;    /* слишком плохо */
 19092	        if (*ap != NULL) {
 19093	                v = (vir_bytes) *ap;    /* v - относительный указатель */
 19094	                v += base;              /* его перемещение */
 19095	                *ap = (char *) v;       /* перемещение обратно */
 19096	        } else {
 19097	                flag++;
 19098	        }
 19099	        ap++;
 19100	  }
 19101	}
	
 19103	/*===========================================================================*
 19104	 *                              insert_arg                                   *
 19105	 *===========================================================================*/
 19106	PRIVATE int insert_arg(stack, stk_bytes, arg, replace)
 19107	char stack[ARG_MAX];            /* указатель на образ стека внутри менеджера процессов */
 19108	vir_bytes *stk_bytes;           /* размер начального стека */
 19109	char *arg;                      /* аргумент для присоединения спереди/удаления в качестве argv[0] */
 19110	int replace;
 19111	{
 19112	/* Организовать стек так, чтобы arg стал argv[0]. Будьте аккуратны, в стеке может
 19113	 * находиться мусор, хотя обычно он имеет следующую структуру: 
 19114	 *      nargs argv[0] ... argv[nargs-1] NULL envp[0] ... NULL
 19115	 * За ней следуют строки, на которые указывают argv[i] и envp[i]. Указатели
 19116	 * на самом деле представляют собой смещения от начала стека.
 19117	 * Возвращает true, если операция завершилась удачно.
 19118	 */
 19119	  int offset, a0, a1, old_bytes = *stk_bytes;
 19120	
 19121	  /* При добавлении arg добавляется как минимум одна строка и нулевой байт. */
 19122	  offset = strlen(arg) + 1;
 19123	
 19124	  a0 = (int) ((char **) stack)[1];      /* argv[0] */
 19125	  if (a0 < 4 * PTRSIZE || a0 >= old_bytes) return(FALSE);
 19126	
 19127	  a1 = a0;                      /* a1 будет указывать на перемещаемые строки */
 19128	  if (replace) {
 19129	        /* Переместить a1 в конец argv[0][] (argv[1] if nargs > 1). */
 19130	        do {
 19131	                if (a1 == old_bytes) return(FALSE);
 19132	                --offset;
 19133	        } while (stack[a1++] != 0);
 19134	  } else {
 19135	        offset += PTRSIZE;      /* новому argv[0] нужен новый указатель в argv[] */
 19136	        a0 += PTRSIZE;          /* расположение нового argv[0][]. */
 19137	  }
 19138	
 19139	  /* стек будет расти на offset байт (или сокращаться на -offset байт) */
 19140	  if ((*stk_bytes += offset) > ARG_MAX) return(FALSE);
 19141	
 19142	  /* Изменение положения строк на offset байт */
 19143	  memmove(stack + a1 + offset, stack + a1, old_bytes - a1);
 19144	
 19145	  strcpy(stack + a0, arg);      /* Помещение arg в новое пространство. */
 19146	
 19147	  if (!replace) {
 19148	        /* Подготовка места для нового argv[0]. */
 19149	        memmove(stack + 2 * PTRSIZE, stack + 1 * PTRSIZE, a0 - 2 * PTRSIZE);
 19150	
 19151	        ((char **) stack)[0]++; /* nargs++; */
 19152	  }
 19153	  /* Смещение argv[] и envp[] на offset. */
 19154	  patch_ptr(stack, (vir_bytes) offset);
 19155	  ((char **) stack)[1] = (char *) a0;   /* установка правильного значения argv[0] */
 19156	  return(TRUE);
 19157	}
	
 19159	/*===========================================================================*
 19160	 *                              patch_stack                                  *
 19161	 *===========================================================================*/
 19162	PRIVATE char *patch_stack(fd, stack, stk_bytes, script)
 19163	int fd;                         /* дескриптор для открытия сценария */
 19164	char stack[ARG_MAX];            /* указатель на образ стека внутри менеджера процессов */
 19165	vir_bytes *stk_bytes;           /* размер начального стека */
 19166	char *script;                   /* имя интерпретируемого сценария */
 19167	{
 19168	/* Включение в вектор аргументов имени сценария и всех строк из строки  #!.
 19169	 * Возвращает путь к интерпретатору.
 19170	 *
 19171	 */
 19172	  char *sp, *interp = NULL;
 19173	  int n;
 19174	  enum { INSERT=FALSE, REPLACE=TRUE };
 19175	
 19176	  /* Делаем script[] новым argv[0]. */
 19177	  if (!insert_arg(stack, stk_bytes, script, REPLACE)) return(NULL);
 19178	
 19179	  if (lseek(fd, 2L, 0) == -1                    /* сразу за #! */
 19180	    || (n= read(fd, script, PATH_MAX)) < 0      /* чтение одной строки */
 19181	    || (sp= memchr(script, '\n', n)) == NULL)   /* должна быть надлежащая строка */
 19182	        return(NULL);
 19183	
 19184	  /* Перемещение sp назад через script[], присоединение каждой строки к стеку. */
 19185	  for (;;) {
 19186	        /* пропуск пробелов после аргумента. */
 19187	        while (sp > script && (*--sp == ' ' || *sp == '\t')) {}
 19188	        if (sp == script) break;
 19189	
 19190	        sp[1] = 0;
 19191	        /* Перемещение в начало аргумента. */
 19192	        while (sp > script && sp[-1] != ' ' && sp[-1] != '\t') --sp;
 19193	
 19194	        interp = sp;
 19195	        if (!insert_arg(stack, stk_bytes, sp, INSERT)) return(NULL);
 19196	  }
 19197	
 19198	  /* Округление *stk_bytes до размера указателя для выравнивания. */
 19199	  *stk_bytes= ((*stk_bytes + PTRSIZE - 1) / PTRSIZE) * PTRSIZE;
 19200	
 19201	  close(fd);
 19202	  return(interp);
 19203	}
	
 19205	/*===========================================================================*
 19206	 *                              rw_seg                                       *
 19207	 *===========================================================================*/
 19208	PUBLIC void rw_seg(rw, fd, proc, seg, seg_bytes0)
 19209	int rw;                         /* 0 = чтение, 1 = запись */
 19210	int fd;                         /* дескриптор считываемого/записываемого файла */
 19211	int proc;                       /* номер процесса */
 19212	int seg;                        /* T, D, или S */
 19213	phys_bytes seg_bytes0;          /* сколько данных? */
 19214	{
 19215	/* Передача кода или данных из файла или в файл и копирование в сегмент или из сегмента процесса.
 19216	 * В этой процедуре имеются хитрости. Логичным способом передачи было бы
 19217	 * копирование блока за блоком из пользовательского пространства и обратно. Это слишком
 19218	 * медленно, поэтому здесь мы применим нечестный метод, а именно пошлем пространство
 19219	 * пользователя и виртуальный адрес файловой системе в 10 верхних битах дескриптора
 19220	 * файла и передадим ей пользовательский виртуальный адрес вместо адреса менеджера
 19221	 * процессов. Файловая система извлечет эти параметры при получении вызова read или write
 19222	 * от менеджера процессов, которой является единственным процессом, способным выполнить
 19223	 * этот трюк. Затем файловая система напрямую копирует сегмент целиком в пространство 
 19224	 * пользователя и обратно, целиком пропуская менеджер процессов.
 19225	 *
 19226	 * Счетчик байтов при чтении обычно меньше счетчика сегмента, поскольку сегмент заполняется
 19227	 * так, чтобы размещаться в целом числе кликов, а сегмент данных инициализирован лишь
 19228	 * частично.
 19229	 */
 19230	
 19231	  int new_fd, bytes, r;
 19232	  char *ubuf_ptr;
 19233	  struct mem_map *sp = &mproc[proc].mp_seg[seg];
 19234	  phys_bytes seg_bytes = seg_bytes0;
 19235	
 19236	  new_fd = (proc << 7) | (seg << 5) | fd;
 19237	  ubuf_ptr = (char *) ((vir_bytes) sp->mem_vir << CLICK_SHIFT);
 19238	
 19239	  while (seg_bytes != 0) {
 19240	#define PM_CHUNK_SIZE 8192
 19241	        bytes = MIN((INT_MAX / PM_CHUNK_SIZE) * PM_CHUNK_SIZE, seg_bytes);
 19242	        if (rw == 0) {
 19243	                r = read(new_fd, ubuf_ptr, bytes);
 19244	        } else {
 19245	                r = write(new_fd, ubuf_ptr, bytes);
 19246	        }
 19247	        if (r != bytes) break;
 19248	        ubuf_ptr += bytes;
 19249	        seg_bytes -= bytes;
 19250	  }
 19251	}
	
 19253	/*===========================================================================*
 19254	 *                              find_share                                   *
 19255	 *===========================================================================*/
 19256	PUBLIC struct mproc *find_share(mp_ign, ino, dev, ctime)
 19257	struct mproc *mp_ign;           /* процесс, который следует проигнорировать */
 19258	ino_t ino;                      /* параметры, уникально идентифицирующие файл */
 19259	dev_t dev;
 19260	time_t ctime;
 19261	{
 19262	/* Процесс, который является исполняемым файлом <ino, dev, ctime>. Процесс mp_ign 
 19263	 * игнорируется, поскольку это процесс, от имени которого совершается системный
 19264	 * вызов.
 19265	 */
 19266	  struct mproc *sh_mp;
 19267	  for (sh_mp = &mproc[0]; sh_mp < &mproc[NR_PROCS]; sh_mp++) {
 19268	
 19269	        if (!(sh_mp->mp_flags & SEPARATE)) continue;
 19270	        if (sh_mp == mp_ign) continue;
 19271	        if (sh_mp->mp_ino != ino) continue;
 19272	        if (sh_mp->mp_dev != dev) continue;
 19273	        if (sh_mp->mp_ctime != ctime) continue;
 19274	        return sh_mp;
 19275	  }
 19276	  return(NULL);
 19277	}



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/break.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 19300	/* Модель выделения памяти в MINIX резервирует фиксированную область памяти для
 19301	 * объединенных сегментов кода, данных и стека. Дочернему процессу, созданному FORK,
 19302	 * выделяется столько же места, сколько и родительскому процессу. Если позднее дочерний
 19303	 * процесс совершает вызов EXEC, новый размер извлекается из заголовка запущенного файла.
 19304	 *
 19305	 * Память процесса включает в себя сегмент кода, затем сегмент данных, затем дыру 
 19306	 * (неиспользуемую память) и сегмент стека.
 19307	 * Сегмент данных растет вверх, а сегмент стека - вниз, поэтому каждый из них может
 19308	 * брать память из дыры. При столкновении сегментов процесс должен быть уничтожен.
 19309	 * процедуры этого файла обеспечивают рост сегментов данных и стека.
 19310	 *
 19311	 * Файл имеет следующие точки входа: 
 19312	 *   do_brk:       системные вызовы BRK/SBRK, расширяющие или сокращающие сегмент данных
 19313	 *   adjust:       проверка, разрешено ли требуемое изменение сегмента
 19314	 *   size_ok:      проверка допустимости размеров сегментов
 19315	 */
 19316	
 19317	#include "pm.h"
 19318	#include <signal.h>
 19319	#include "mproc.h"
 19320	#include "param.h"
 19321	
 19322	#define DATA_CHANGED       1    /* флаг, устанавливаемый при изменении размера сегмента данных */
 19323	#define STACK_CHANGED      2    /* флаг, устанавливаемый при изменении размера сегмента стека */
 19324	
 19325	/*===========================================================================*
 19326	 *                              do_brk                                       *
 19327	 *===========================================================================*/
 19328	PUBLIC int do_brk()
 19329	{
 19330	/* Выполнение системного вызова brk(addr).
 19331	 *
 19332	 * Вызов усложнен тем, что на некоторых компьютерах (например, на 8088) указатель стека
 19333	 * может выходить за пределы базового адреса сегмента стека, причем никто об этом не
 19334	 * оповещается.
 19335	 * параметр 'addr' - новый виртуальный адрес в пространстве данных.
 19336	 */
 19337	
 19338	  register struct mproc *rmp;
 19339	  int r;
 19340	  vir_bytes v, new_sp;
 19341	  vir_clicks new_clicks;
 19342	
 19343	  rmp = mp;
 19344	  v = (vir_bytes) m_in.addr;
 19345	  new_clicks = (vir_clicks) ( ((long) v + CLICK_SIZE - 1) >> CLICK_SHIFT);
 19346	  if (new_clicks < rmp->mp_seg[D].mem_vir) {
 19347	        rmp->mp_reply.reply_ptr = (char *) -1;
 19348	        return(ENOMEM);
 19349	  }
 19350	  new_clicks -= rmp->mp_seg[D].mem_vir;
 19351	  if ((r=get_stack_ptr(who, &new_sp)) != OK)    /* запрос значения sp у ядра */
 19352	        panic(__FILE__,"couldn't get stack pointer", r);
 19353	  r = adjust(rmp, new_clicks, new_sp);
 19354	  rmp->mp_reply.reply_ptr = (r == OK ? m_in.addr :  (char *) -1);
 19355	  return(r);                    /* возврат нового адреса -1 */
 19356	}
	
 19358	/*===========================================================================*
 19359	 *                              adjust                                       *
 19360	 *===========================================================================*/
 19361	PUBLIC int adjust(rmp, data_clicks, sp)
 19362	register struct mproc *rmp;     /* процесс, для которого выполняется подгонка памяти */
 19363	vir_clicks data_clicks;         /* новый размер сегмента данных */
 19364	vir_bytes sp;                   /* новое значение указателя стека */
 19365	{
 19366	/* Проверка возможности совместного существования сегментов данных и стека, при необходимости
 19367	 * их подгонка. Память никогда не выделяется и не освобождается. Вместо этого память
 19368	 * добавляется в дыру или удаляется из дыры между сегментами данных и стека. Если размер
 19369	 * дыры становится отрицательным, подгонка данных и стека оказывается неудачной и возвращается ENOMEM.
 19370	 */
 19371	
 19372	  register struct mem_map *mem_sp, *mem_dp;
 19373	  vir_clicks sp_click, gap_base, lower, old_clicks;
 19374	  int changed, r, ft;
 19375	  long base_of_stack, delta;    /* тип long позволяет избежать некоторых проблем */
 19376	
 19377	  mem_dp = &rmp->mp_seg[D];     /* указатель на карту сегмента данных */
 19378	  mem_sp = &rmp->mp_seg[S];     /* указатель на карту сегмента стека */
 19379	  changed = 0;                  /* устанавливается при изменении какого-либо сегмента */
 19380	
 19381	  if (mem_sp->mem_len == 0) return(OK);
 19382	
 19383	  /* Определить, стал ли размер стека отрицательным (то есть sp слишком близок к 0xFFFF...) */
 19384	  base_of_stack = (long) mem_sp->mem_vir + (long) mem_sp->mem_len;
 19385	  sp_click = sp >> CLICK_SHIFT; /* клик, содержащий sp */
 19386	  if (sp_click >= base_of_stack) return(ENOMEM);        /* sp слишком высоко */
 19387	
 19388	  /* Вычислить размер дыры между сегментами стека и данных. */
 19389	  delta = (long) mem_sp->mem_vir - (long) sp_click;
 19390	  lower = (delta > 0 ? sp_click :  mem_sp->mem_vir);
 19391	
 19392	  /* Добавить безопасную границу для роста стека в будущем. Невозможно сделать правильно. */
 19393	#define SAFETY_BYTES  (384 * sizeof(char *))
 19394	#define SAFETY_CLICKS ((SAFETY_BYTES + CLICK_SIZE - 1) / CLICK_SIZE)
 19395	  gap_base = mem_dp->mem_vir + data_clicks + SAFETY_CLICKS;
 19396	  if (lower < gap_base) return(ENOMEM); /* данные и стек перекрылись */
 19397	
 19398	  /* Обновление длины (но не начала) данных от имени системного вызова brk(). */
 19399	  old_clicks = mem_dp->mem_len;
 19400	  if (data_clicks != mem_dp->mem_len) {
 19401	        mem_dp->mem_len = data_clicks;
 19402	        changed |= DATA_CHANGED;
 19403	  }
 19404	
 19405	  /* Обновление длины и начала стека из-за изменения указателя стека. */
 19406	  if (delta > 0) {
 19407	        mem_sp->mem_vir -= delta;
 19408	        mem_sp->mem_phys -= delta;
 19409	        mem_sp->mem_len += delta;
 19410	        changed |= STACK_CHANGED;
 19411	  }
 19412	
 19413	  /* Умещаются ли сегменты данных и стека с новыми размерами в адресном пространстве? */
 19414	  ft = (rmp->mp_flags & SEPARATE);
 19415	  r = (rmp->mp_seg[D].mem_vir + rmp->mp_seg[D].mem_len > 
 19416	          rmp->mp_seg[S].mem_vir) ? ENOMEM :  OK;
 19417	  if (r == OK) {
 19418	        if (changed) sys_newmap((int)(rmp - mproc), rmp->mp_seg);
 19419	        return(OK);
 19420	  }
 19421	
 19422	  /* Новые размеры не помещаются или требуют слишком много страничных/сегментных регистров. Восстановление. */
 19423	  if (changed & DATA_CHANGED) mem_dp->mem_len = old_clicks;
 19424	  if (changed & STACK_CHANGED) {
 19425	        mem_sp->mem_vir += delta;
 19426	        mem_sp->mem_phys += delta;
 19427	        mem_sp->mem_len -= delta;
 19428	  }
 19429	  return(ENOMEM);
 19430	}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/signal.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 19500	/* Этот файл обрабатывает сигналы, которые являются асинхронными событиями и
 19501	 * обычно не представляют собой ничего приятного. Сигналы могут генерироваться
 19502	 * системным вызовом KILL, клавиатурой (SIGINT) или часами (SIGALRM). Во всех
 19503	 * случаях управление в конечном счете передается функции check_sig(), проверяющей,
 19504	 * каким процессам можно послать сигнал. Фактическая отправка сигнала осуществляется функцией sig_proc().
 19505	 *
 19506	 * Файл имеет следующие точки входа: 
 19507	 *   do_sigaction:    выполнение системного вызова SIGACTION
 19508	 *   do_sigpending:   выполнение системного вызова SIGPENDING
 19509	 *   do_sigprocmask:  выполнение системного вызова SIGPROCMASK
 19510	 *   do_sigreturn:    выполнение системного вызова SIGRETURN
 19511	 *   do_sigsuspend:   выполнение системного вызова SIGSUSPEND
 19512	 *   do_kill:         выполнение системного вызова KILL
 19513	 *   do_alarm:        выполнение системного вызова ALARM вызовом set_alarm()
 19514	 *   set_alarm:       указание таймерному заданию запустить или остановить таймер
 19515	 *   do_pause:        выполнение системного вызова PAUSE
 19516	 *   ksig_pending:    ядро получает уведомление об активных сигналах
 19517	 *   sig_proc:        прерывание или завершение процесса, которому посылается сигнал
 19518	 *   check_sig:       проверка, каким процессам послать сигнал вызовом sig_proc()
 19519	 *   check_pending:   проверка, может ли активный сигнал быть доставлен
 19520	 */
 19521	
 19522	#include "pm.h"
 19523	#include <sys/stat.h>
 19524	#include <sys/ptrace.h>
 19525	#include <minix/callnr.h>
 19526	#include <minix/com.h>
 19527	#include <signal.h>
 19528	#include <sys/sigcontext.h>
 19529	#include <string.h>
 19530	#include "mproc.h"
 19531	#include "param.h"
 19532	
 19533	#define CORE_MODE       0777    /* режим, используемый для файлов образов памяти */
 19534	#define DUMPED          0200    /* бит, устанавливаемый согласно состоянию при создании дампа */
 19535	
 19536	FORWARD _PROTOTYPE( void dump_core, (struct mproc *rmp)                 );
 19537	FORWARD _PROTOTYPE( void unpause, (int pro)                             );
 19538	FORWARD _PROTOTYPE( void handle_sig, (int proc_nr, sigset_t sig_map)    );
 19539	FORWARD _PROTOTYPE( void cause_sigalrm, (struct timer *tp)              );
 19540	
 19541	/*===========================================================================*
 19542	 *                              do_sigaction                                 *
 19543	 *===========================================================================*/
 19544	PUBLIC int do_sigaction()
 19545	{
 19546	  int r;
 19547	  struct sigaction svec;
 19548	  struct sigaction *svp;
 19549	
 19550	  if (m_in.sig_nr == SIGKILL) return(OK);
 19551	  if (m_in.sig_nr < 1 || m_in.sig_nr > _NSIG) return (EINVAL);
 19552	  svp = &mp->mp_sigact[m_in.sig_nr];
 19553	  if ((struct sigaction *) m_in.sig_osa != (struct sigaction *) NULL) {
 19554	        r = sys_datacopy(PM_PROC_NR,(vir_bytes) svp,
 19555	                who, (vir_bytes) m_in.sig_osa, (phys_bytes) sizeof(svec));
 19556	        if (r != OK) return(r);
 19557	  }
 19558	
 19559	  if ((struct sigaction *) m_in.sig_nsa == (struct sigaction *) NULL) 
 19560	        return(OK);
 19561	
 19562	  /* Изучение структуры sigaction. */
 19563	  r = sys_datacopy(who, (vir_bytes) m_in.sig_nsa,
 19564	                PM_PROC_NR, (vir_bytes) &svec, (phys_bytes) sizeof(svec));
 19565	  if (r != OK) return(r);
 19566	
 19567	  if (svec.sa_handler == SIG_IGN) {
 19568	        sigaddset(&mp->mp_ignore, m_in.sig_nr);
 19569	        sigdelset(&mp->mp_sigpending, m_in.sig_nr);
 19570	        sigdelset(&mp->mp_catch, m_in.sig_nr);
 19571	        sigdelset(&mp->mp_sig2mess, m_in.sig_nr);
 19572	  } else if (svec.sa_handler == SIG_DFL) {
 19573	        sigdelset(&mp->mp_ignore, m_in.sig_nr);
 19574	        sigdelset(&mp->mp_catch, m_in.sig_nr);
 19575	        sigdelset(&mp->mp_sig2mess, m_in.sig_nr);
 19576	  } else if (svec.sa_handler == SIG_MESS) {
 19577	        if (! (mp->mp_flags & PRIV_PROC)) return(EPERM);
 19578	        sigdelset(&mp->mp_ignore, m_in.sig_nr);
 19579	        sigaddset(&mp->mp_sig2mess, m_in.sig_nr);
 19580	        sigdelset(&mp->mp_catch, m_in.sig_nr);
 19581	  } else {
 19582	        sigdelset(&mp->mp_ignore, m_in.sig_nr);
 19583	        sigaddset(&mp->mp_catch, m_in.sig_nr);
 19584	        sigdelset(&mp->mp_sig2mess, m_in.sig_nr);
 19585	  }
 19586	  mp->mp_sigact[m_in.sig_nr].sa_handler = svec.sa_handler;
 19587	  sigdelset(&svec.sa_mask, SIGKILL);
 19588	  mp->mp_sigact[m_in.sig_nr].sa_mask = svec.sa_mask;
 19589	  mp->mp_sigact[m_in.sig_nr].sa_flags = svec.sa_flags;
 19590	  mp->mp_sigreturn = (vir_bytes) m_in.sig_ret;
 19591	  return(OK);
 19592	}
	
 19594	/*===========================================================================*
 19595	 *                              do_sigpending                                *
 19596	 *===========================================================================*/
 19597	PUBLIC int do_sigpending()
 19598	{
 19599	  mp->mp_reply.reply_mask = (long) mp->mp_sigpending;
 19600	  return OK;
 19601	}
	
 19603	/*===========================================================================*
 19604	 *                              do_sigprocmask                               *
 19605	 *===========================================================================*/
 19606	PUBLIC int do_sigprocmask()
 19607	{
 19608	/* Обратите внимание на то, что для сохранения копии библиотечный интерфейс передает
 19609	 * в sigmask_set фактическую маску,а не указатель на нее. Аналогично, старая маска
 19610	 * помещается в ответное сообщение, которое библиотечный интерфейс копирует (по
 19611	 * запросу) в адрес, указанный пользователем.
 19612	 *
 19613	 * Библиотечный интрфейс должен установить SIG_INQUIRE, если аргумент 'act' равен
 19614	 * NULL.
 19615	 */
 19616	
 19617	  int i;
 19618	
 19619	  mp->mp_reply.reply_mask = (long) mp->mp_sigmask;
 19620	
 19621	  switch (m_in.sig_how) {
 19622	      case SIG_BLOCK: 
 19623	        sigdelset((sigset_t *)&m_in.sig_set, SIGKILL);
 19624	        for (i = 1; i <= _NSIG; i++) {
 19625	                if (sigismember((sigset_t *)&m_in.sig_set, i))
 19626	                        sigaddset(&mp->mp_sigmask, i);
 19627	        }
 19628	        break;
 19629	
 19630	      case SIG_UNBLOCK: 
 19631	        for (i = 1; i <= _NSIG; i++) {
 19632	                if (sigismember((sigset_t *)&m_in.sig_set, i))
 19633	                        sigdelset(&mp->mp_sigmask, i);
 19634	        }
 19635	        check_pending(mp);
 19636	        break;
 19637	
 19638	      case SIG_SETMASK: 
 19639	        sigdelset((sigset_t *) &m_in.sig_set, SIGKILL);
 19640	        mp->mp_sigmask = (sigset_t) m_in.sig_set;
 19641	        check_pending(mp);
 19642	        break;
 19643	
 19644	      case SIG_INQUIRE: 
 19645	        break;
 19646	
 19647	      default: 
 19648	        return(EINVAL);
 19649	        break;
 19650	  }
 19651	  return OK;
 19652	}
	
 19654	/*===========================================================================*
 19655	 *                              do_sigsuspend                                *
 19656	 *===========================================================================*/
 19657	PUBLIC int do_sigsuspend()
 19658	{
 19659	  mp->mp_sigmask2 = mp->mp_sigmask;     /* сохранение старой маски */
 19660	  mp->mp_sigmask = (sigset_t) m_in.sig_set;
 19661	  sigdelset(&mp->mp_sigmask, SIGKILL);
 19662	  mp->mp_flags |= SIGSUSPENDED;
 19663	  check_pending(mp);
 19664	  return(SUSPEND);
 19665	}
	
 19667	/*===========================================================================*
 19668	 *                              do_sigreturn                                 *
 19669	 *===========================================================================*/
 19670	PUBLIC int do_sigreturn()
 19671	{
 19672	/* Обработчик пользовательского сигнала завершил работу. Восстановление контекста и
 19673	 * проверка активных неблокированных сигналов.
 19674	 */
 19675	
 19676	  int r;
 19677	
 19678	  mp->mp_sigmask = (sigset_t) m_in.sig_set;
 19679	  sigdelset(&mp->mp_sigmask, SIGKILL);
 19680	
 19681	  r = sys_sigreturn(who, (struct sigmsg *) m_in.sig_context);
 19682	  check_pending(mp);
 19683	  return(r);
 19684	}
	
 19686	/*===========================================================================*
 19687	 *                              do_kill                                      *
 19688	 *===========================================================================*/
 19689	PUBLIC int do_kill()
 19690	{
 19691	/* Выполнение системного вызова kill(pid, signo). */
 19692	
 19693	  return check_sig(m_in.pid, m_in.sig_nr);
 19694	}
	
 19696	/*===========================================================================*
 19697	 *                              ksig_pending                                 *
 19698	 *===========================================================================*/
 19699	PUBLIC int ksig_pending()
 19700	{
 19701	/* Определенные сигналы, такие как нарушение сегментации, посылаются ядром. Когда
 19702	 * ядро обнаруживает подобные сигналы, оно уведомляет менеджер процессов о том, что
 19703	 * нужно выполнить дальнейшие действия. Менеджер процессов запрашивает у ядра сообщение с
 19704	 * записью процесса и битовой картой всех процессов, которым был послан сигнал. К примеру,
 19705	 * файловая система использует этот механизм для оповещения о записи в разорванный канал (сигнал SIGPIPE). 
 19706	 *
 19707	 * Ядро уведомило менеджера процессов об активных сигналах. Активные сигналы запрашиваются
 19708	 * до тех пор, пока все сигналы не будут обработаны. При отсутствии сигналов в поле номера
 19709	 * процесса возвращается значение NONE.
 19710	 */ 
 19711	 int proc_nr;
 19712	 sigset_t sig_map;
 19713	
 19714	 while (TRUE) {
 19715	   sys_getksig(&proc_nr, &sig_map);     /* получение произвольного активного сигнала */
 19716	   if (NONE == proc_nr) {               /* останов, если активных сигналов больше нет */
 19717	        break;
 19718	   } else {
 19719	        handle_sig(proc_nr, sig_map);   /* обработка полученного сигнала */
 19720	        sys_endksig(proc_nr);           /* информирование ядра о завершении обработки */
 19721	   }
 19722	 } 
 19723	 return(SUSPEND);                       /* подавляет отправку ответа */
 19724	}
	
 19726	/*===========================================================================*
 19727	 *                              handle_sig                                   *
 19728	 *===========================================================================*/
 19729	PRIVATE void handle_sig(proc_nr, sig_map)
 19730	int proc_nr;
 19731	sigset_t sig_map;
 19732	{
 19733	  register struct mproc *rmp;
 19734	  int i;
 19735	  pid_t proc_id, id;
 19736	
 19737	  rmp = &mproc[proc_nr];
 19738	  if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) return;
 19739	  proc_id = rmp->mp_pid;
 19740	  mp = &mproc[0];                       /* притворяемся, что сигналы посланы менеджером процессов */
 19741	  mp->mp_procgrp = rmp->mp_procgrp;     /* получение правильной группы процессов */
 19742	
 19743	  /* Проверка каждого бита, чтобы определить, нужно ли посылать сигнал. В отличие от
 19744	   * kill(), ядро может собрать несколько несвязанных сигналов для процесса и единовременно
 19745	   * передать их менеджеру процессов. По этой причине используется циклическая обработка
 19746	   * битовой карты. Для SIGINT и SIGQUIT значение 0 переменной proc_id указывает на группу
 19747	   * процесса-приемника. Для SIGKILL значение -1 переменной proc_id указывает
 19748	   * широковещательное сообщение, адресованное всей системе.
 19749	   */
 19750	  for (i = 1; i <= _NSIG; i++) {
 19751	        if (!sigismember(&sig_map, i)) continue;
 19752	        switch (i) {
 19753	            case SIGINT: 
 19754	            case SIGQUIT: 
 19755	                id = 0; break;  /* широковещательное сообщение для группы процессов */
 19756	            case SIGKILL: 
 19757	                id = -1; break; /* широковещательное сообщение для всех процессов, кроме INIT */
 19758	            default: 
 19759	                id = proc_id;
 19760	                break;
 19761	        }
 19762	        check_sig(id, i);
 19763	  }
 19764	}
	
 19766	/*===========================================================================*
 19767	 *                              do_alarm                                     *
 19768	 *===========================================================================*/
 19769	PUBLIC int do_alarm()
 19770	{
 19771	/* Выполнение системного вызова alarm(seconds). */
 19772	  return(set_alarm(who, m_in.seconds));
 19773	}
	
 19775	/*===========================================================================*
 19776	 *                              set_alarm                                    *
 19777	 *===========================================================================*/
 19778	PUBLIC int set_alarm(proc_nr, sec)
 19779	int proc_nr;                    /* Процесс, желающий получить оповещение */
 19780	int sec;                        /* задержка передачи сигнала в секундах */
 19781	{
 19782	/* Эта процедура используется функцией do_alarm() для установки таймера оповещения.
 19783	 * Она также используется для выключения таймера, когда процесс завершает свою работу до его истечения 
 19784	 */
 19785	  clock_t ticks;        /* число тактов для оповещения */
 19786	  clock_t exptime;      /* оставшееся время предыдущего оповещения */
 19787	  clock_t uptime;       /* текущее системное время */
 19788	  int remaining;        /* предыдущее оставшееся время в секундах */
 19789	  int s;
 19790	
 19791	  /* Сначала определение времени предыдущего оповещения, если оно было. */
 19792	  if (mproc[proc_nr].mp_flags & ALARM_ON) {
 19793	        if ( (s=getuptime(&uptime)) != OK) 
 19794	                panic(__FILE__,"set_alarm couldn't get uptime", s);
 19795	        exptime = *tmr_exp_time(&mproc[proc_nr].mp_timer);
 19796	        remaining = (int) ((exptime - uptime + (HZ-1))/HZ);
 19797	        if (remaining < 0) remaining = 0;       
 19798	  } else {
 19799	        remaining = 0; 
 19800	  }
 19801	
 19802	  /* Указание заданию ядра создать сигнальное сообщение в нужный момент времени.
 19803	   *
 19804	   * Длительные задержки создают множество проблем. Во-первых, системный вызов alarm
 19805	   * принимает беззнаковое число секунд, и библиотека приводит его к типу int. Возможно,
 19806	   * это работает, но при возврате библиотека считает "отрицательные" беззнаковые числа
 19807	   * ошибками. По-видимому, никто не проверяет эти ошибки, поэтому выполнение вызова 
 19808	   * продолжается. Во-вторых, если типы unsigned и long имеют одинаковый
 19809	   * размер, преобразование из секунд в такты может легко вызвать переполнение. В-третьих,
 19810	   * аналогичные ошибки возможны в ядре при сложении тактов.
 19811	   *
 19812	   * Для решения проблем требуется множество неприятных приведений типов. Константа 
 19813	   * ALRM_EXP_TIME имеет правильный тип (clock_t), хотя и объявлена как long.
 19814	   * Как правильно объявлять подобные переменные, избегая "комбинаторного взрыва" типов
 19815	   * сообщений?
 19816	   *
 19817	   */
 19818	  ticks = (clock_t) (HZ * (unsigned long) (unsigned) sec);
 19819	  if ( (unsigned long) ticks / HZ != (unsigned) sec)
 19820	        ticks = LONG_MAX;       /* бесконечность (на самом деле TMR_NEVER) */
 19821	
 19822	  if (ticks != 0) {
 19823	        pm_set_timer(&mproc[proc_nr].mp_timer, ticks, cause_sigalrm, proc_nr);
 19824	        mproc[proc_nr].mp_flags |=  ALARM_ON;
 19825	  } else if (mproc[proc_nr].mp_flags & ALARM_ON) {
 19826	        pm_cancel_timer(&mproc[proc_nr].mp_timer);
 19827	        mproc[proc_nr].mp_flags &= ~ALARM_ON;
 19828	  }
 19829	  return(remaining);
 19830	}
	
 19832	/*===========================================================================*
 19833	 *                              cause_sigalrm                                *
 19834	 *===========================================================================*/
 19835	PRIVATE void cause_sigalrm(tp)
 19836	struct timer *tp;
 19837	{
 19838	  int proc_nr;
 19839	  register struct mproc *rmp;
 19840	
 19841	  proc_nr = tmr_arg(tp)->ta_int;        /* получение процесса по таймеру */
 19842	  rmp = &mproc[proc_nr];
 19843	
 19844	  if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) return;
 19845	  if ((rmp->mp_flags & ALARM_ON) == 0) return;
 19846	  rmp->mp_flags &= ~ALARM_ON;
 19847	  check_sig(rmp->mp_pid, SIGALRM);
 19848	}
	
 19850	/*===========================================================================*
 19851	 *                              do_pause                                     *
 19852	 *===========================================================================*/
 19853	PUBLIC int do_pause()
 19854	{
 19855	/* Выполнение системного вызова pause(). */
 19856	
 19857	  mp->mp_flags |= PAUSED;
 19858	  return(SUSPEND);
 19859	}
	
 19861	/*===========================================================================*
 19862	 *                              sig_proc                                     *
 19863	 *===========================================================================*/
 19864	PUBLIC void sig_proc(rmp, signo)
 19865	register struct mproc *rmp;     /* указатель на процесс, которому требуется послать сигнал */
 19866	int signo;                      /* посылаемый сигнал (от 1 до _NSIG) */
 19867	{
 19868	/* Передача сигнала процессу. Определение, следует ли перехватить сигнал, проигнорировать,
 19869	 * преобразовать в сообщение (для системных процессов) или блокировать.  
 19870	 *  - Если сигнал должен быть преобразован в сообщение, запросить ядро
 19871	 * послать процессу системное уведомление с активным сигналом в качестве
 19872	 * аргумента. 
 19873	 *  - Если сигнал должен быть перехвачен, запросить ядро поместить 
 19874	 * структуры sigcontext и sigframe в стек перехватчика. Ядро сбросит
 19875	 * счетчик команд и стека, чтобы при следующем запуске процесса он 
 19876	 * выполнил обработчик сигнала. После возврата из обработчика сигнала
 19877	 * произойдет вызов sigreturn(2), а затем ядро восстановит контекст 
 19878	 * сигнала из структуры sigcontext.
 19879	 * При недостаточном объеме стека уничтожить процесс.
 19880	 */
 19881	
 19882	  vir_bytes new_sp;
 19883	  int s;
 19884	  int slot;
 19885	  int sigflags;
 19886	  struct sigmsg sm;
 19887	
 19888	  slot = (int) (rmp - mproc);
 19889	  if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) {
 19890	        printf("PM:  signal %d sent to %s process %d\n",
 19891	                signo, (rmp->mp_flags & ZOMBIE) ? "zombie" :  "dead", slot);
 19892	        panic(__FILE__,"", NO_NUM);
 19893	  }
 19894	  if ((rmp->mp_flags & TRACED) && signo != SIGKILL) {
 19895	        /* Трассируемый процесс обрабатывается особо. */
 19896	        unpause(slot);
 19897	        stop_proc(rmp, signo);  /* a signal causes it to stop */
 19898	        return;
 19899	  }
 19900	  /* Некоторые сигналы по умолчанию игнорируются. */
 19901	  if (sigismember(&rmp->mp_ignore, signo)) { 
 19902	        return;
 19903	  }
 19904	  if (sigismember(&rmp->mp_sigmask, signo)) {
 19905	        /* Сигнал следует блокировать. */
 19906	        sigaddset(&rmp->mp_sigpending, signo);
 19907	        return;
 19908	  }
 19909	  sigflags = rmp->mp_sigact[signo].sa_flags;
 19910	  if (sigismember(&rmp->mp_catch, signo)) {
 19911	        if (rmp->mp_flags & SIGSUSPENDED)
 19912	                sm.sm_mask = rmp->mp_sigmask2;
 19913	        else
 19914	                sm.sm_mask = rmp->mp_sigmask;
 19915	        sm.sm_signo = signo;
 19916	        sm.sm_sighandler = (vir_bytes) rmp->mp_sigact[signo].sa_handler;
 19917	        sm.sm_sigreturn = rmp->mp_sigreturn;
 19918	        if ((s=get_stack_ptr(slot, &new_sp)) != OK)
 19919	                panic(__FILE__,"couldn't get new stack pointer",s);
 19920	        sm.sm_stkptr = new_sp;
 19921	
 19922	        /* Выделить место под структуры sigcontext и sigframe. */
 19923	        new_sp -= sizeof(struct sigcontext)
 19924	                                 + 3 * sizeof(char *) + 2 * sizeof(int);
 19925	
 19926	        if (adjust(rmp, rmp->mp_seg[D].mem_len, new_sp) != OK)
 19927	                goto doterminate;
 19928	
 19929	        rmp->mp_sigmask |= rmp->mp_sigact[signo].sa_mask;
 19930	        if (sigflags & SA_NODEFER)
 19931	                sigdelset(&rmp->mp_sigmask, signo);
 19932	        else
 19933	                sigaddset(&rmp->mp_sigmask, signo);
 19934	
 19935	        if (sigflags & SA_RESETHAND) {
 19936	                sigdelset(&rmp->mp_catch, signo);
 19937	                rmp->mp_sigact[signo].sa_handler = SIG_DFL;
 19938	        }
 19939	
 19940	        if (OK == (s=sys_sigsend(slot, &sm))) {
 19941	
 19942	                sigdelset(&rmp->mp_sigpending, signo);
 19943	                /* Если процесс ожидает PAUSE, WAIT, SIGSUSPEND, терминал, 
 19944	                 * канал и т. д., освободить его.
 19945	                 */
 19946	                unpause(slot);
 19947	                return;
 19948	        }
 19949	        panic(__FILE__, "warning, sys_sigsend failed", s);
 19950	  }
 19951	  else if (sigismember(&rmp->mp_sig2mess, signo)) {
 19952	        if (OK != (s=sys_kill(slot,signo)))
 19953	                panic(__FILE__, "warning, sys_kill failed", s);
 19954	        return;
 19955	  }
 19956	
 19957	doterminate: 
 19958	  /* Сигнал не должен или не может быть перехвачен. Выполнить действие по умолчанию. */
 19959	  if (sigismember(&ign_sset, signo)) return;
 19960	
 19961	  rmp->mp_sigstatus = (char) signo;
 19962	  if (sigismember(&core_sset, signo)) {
 19963	        /* Переключиться в окружение файловой системы пользователя и создать дамп ядра. */
 19964	        tell_fs(CHDIR, slot, FALSE, 0);
 19965	        dump_core(rmp);
 19966	  }
 19967	  pm_exit(rmp, 0);              /* завершить процесс */
 19968	}
	
 19970	/*===========================================================================*
 19971	 *                              check_sig                                    *
 19972	 *===========================================================================*/
 19973	PUBLIC int check_sig(proc_id, signo)
 19974	pid_t proc_id;                  /* pid процесса, которому посылается сигнал, 0, -1, или -pgrp */
 19975	int signo;                      /* сигнал, посылаемый процессу (от 0 to _NSIG) */
 19976	{
 19977	/* Проверка возможности послать сигнал. Сигнал может быть необходимо послать группе
 19978	 * процессов. Эта процедура вызывается системным вызовом KILL, а также при перехвате
 19979	 * ядром DEL или другого сигнал.
 19980	 */
 19981	
 19982	  register struct mproc *rmp;
 19983	  int count;                    /* счетчик посланных сигналов */
 19984	  int error_code;
 19985	
 19986	  if (signo < 0 || signo > _NSIG) return(EINVAL);
 19987	
 19988	  /* Возврат EINVAL для попыток послать SIGKILL только процессу INIT. */
 19989	  if (proc_id == INIT_PID && signo == SIGKILL) return(EINVAL);
 19990	
 19991	  /* Поиск в таблице процессов тех процессов, которым нужно послать сигнал.  (см.
 19992	   * forkexit.c о магических значениях pid)
 19993	   */
 19994	  count = 0;
 19995	  error_code = ESRCH;
 19996	  for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
 19997	        if (!(rmp->mp_flags & IN_USE)) continue;
 19998	        if ((rmp->mp_flags & ZOMBIE) && signo != 0) continue;
 19999	
 20000	        /* Проверка выбора. */
 20001	        if (proc_id > 0 && proc_id != rmp->mp_pid) continue;
 20002	        if (proc_id == 0 && mp->mp_procgrp != rmp->mp_procgrp) continue;
 20003	        if (proc_id == -1 && rmp->mp_pid <= INIT_PID) continue;
 20004	        if (proc_id < -1 && rmp->mp_procgrp != -proc_id) continue;
 20005	
 20006	        /* Проверка разрешения. */
 20007	        if (mp->mp_effuid != SUPER_USER
 20008	            && mp->mp_realuid != rmp->mp_realuid
 20009	            && mp->mp_effuid != rmp->mp_realuid
 20010	            && mp->mp_realuid != rmp->mp_effuid
 20011	            && mp->mp_effuid != rmp->mp_effuid) {
 20012	                error_code = EPERM;
 20013	                continue;
 20014	        }
 20015	
 20016	        count++;
 20017	        if (signo == 0) continue;
 20018	
 20019	        /* 'sig_proc' принимает решение по обработке сигнала. Сигнал
 20020	         * может быть перехвачен, блокирован, игнорирован или может вызвать завершение процесса, 
 20021	         * возможно с созданием дампа ядра.
 20022	         */
 20023	        sig_proc(rmp, signo);
 20024	
 20025	        if (proc_id > 0) break; /* сигнал только для одного процесса */
 20026	  }
 20027	
 20028	  /* Если вызывающий процесс уничтожил себя, не отвечать. */
 20029	  if ((mp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) return(SUSPEND);
 20030	  return(count > 0 ? OK :  error_code);
 20031	}
	
 20033	/*===========================================================================*
 20034	 *                              check_pending                                *
 20035	 *===========================================================================*/
 20036	PUBLIC void check_pending(rmp)
 20037	register struct mproc *rmp;
 20038	{
 20039	  /* Проверка наличия разблокированных активных сигналов. Первый найденный такой
 20040	   * сигнал доставляется приемнику.
 20041	   *
 20042	   * Если обнаруживается несколько активных немаскированных сигналов, их доставка
 20043	   * осуществляется последовательно.
 20044	   *
 20045	   * В этом файле имеется несколько точек, в которых изменяется маска сигналов. В каждой
 20046	   * такой точке нужно вызывать функцию check_pending() для проверки наличия новых
 20047	   * разблокированных сигналов.
 20048	   */
 20049	
 20050	  int i;
 20051	
 20052	  for (i = 1; i <= _NSIG; i++) {
 20053	        if (sigismember(&rmp->mp_sigpending, i) &&
 20054	                !sigismember(&rmp->mp_sigmask, i)) {
 20055	                sigdelset(&rmp->mp_sigpending, i);
 20056	                sig_proc(rmp, i);
 20057	                break;
 20058	        }
 20059	  }
 20060	}
	
 20062	/*===========================================================================*
 20063	 *                              unpause                                      *
 20064	 *===========================================================================*/
 20065	PRIVATE void unpause(pro)
 20066	int pro;                        /* номер процесса */
 20067	{
 20068	/* Необходимо послать сигнал процессу. Если этот процесс ожидает системного вызова,
 20069	 * вызов необходимо завершить с помощью EINTR.  Возможные вызовы: PAUSE, WAIT, READ и
 20070	 * WRITE, два последних – для каналов и терминалов. Сначала проверяется, находится 
 20071	 * ли процесс в ожидании вызова менеджера процессов. Если нет, информировать файловую
 20072	 * систему, чтобы она проверила READ и WRITE для каналов, терминалов и т. п.
 20073	 */
 20074	
 20075	  register struct mproc *rmp;
 20076	
 20077	  rmp = &mproc[pro];
 20078	
 20079	  /* Проверка, находится ли процесс в ожидании вызова PAUSE, WAIT или SIGSUSPEND. */
 20080	  if (rmp->mp_flags & (PAUSED | WAITING | SIGSUSPENDED)) {
 20081	        rmp->mp_flags &= ~(PAUSED | WAITING | SIGSUSPENDED);
 20082	        setreply(pro, EINTR);
 20083	        return;
 20084	  }
 20085	
 20086	  /* Процесс не ожидает вызова менеджера процессов. Обращение к файловой системе для проверки ее вызовов. */
 20087	  tell_fs(UNPAUSE, pro, 0, 0);
 20088	}
	
 20090	/*===========================================================================*
 20091	 *                              dump_core                                    *
 20092	 *===========================================================================*/
 20093	PRIVATE void dump_core(rmp)
 20094	register struct mproc *rmp;     /* ядро для дампа */
 20095	{
 20096	/* создания дампа ядра файла, если возможно. */
 20097	
 20098	  int s, fd, seg, slot;
 20099	  vir_bytes current_sp;
 20100	  long trace_data, trace_off;
 20101	
 20102	  slot = (int) (rmp - mproc);
 20103	
 20104	  /* Можно ли переписать ядро файла?  Мы работаем в окружении файловой системы пользователя,
 20105	   * поэтому специальных проверок разрешений не требуется.
 20106	   */
 20107	  if (rmp->mp_realuid != rmp->mp_effuid) return;
 20108	  if ( (fd = open(core_name, O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK,
 20109	                                                CORE_MODE)) < 0) return;
 20110	  rmp->mp_sigstatus |= DUMPED;
 20111	
 20112	  /* Проверка актуальности сегмента стека.
 20113	   * Мы хотим, чтобы функция adjust() завершалась неудачно только если значение current_sp
 20114	   * некорректно, однако это может произойти и из-за проверки безопасности. Кроме того, мы
 20115	   * не хотим, чтобы при передаче сигнала функция adjust() завершалась неудачно из-за  
 20116	   * проверки безопасности. Возможно, следует сделать SAFETY_BYTES параметром.
 20117	   */
 20118	  if ((s=get_stack_ptr(slot, &current_sp)) != OK)
 20119	        panic(__FILE__,"couldn't get new stack pointer",s);
 20120	  adjust(rmp, rmp->mp_seg[D].mem_len, current_sp);
 20121	
 20122	  /* Запись карты памяти всех сегментов. */
 20123	  if (write(fd, (char *) rmp->mp_seg, (unsigned) sizeof rmp->mp_seg)
 20124	      != (unsigned) sizeof rmp->mp_seg) {
 20125	        close(fd);
 20126	        return;
 20127	  }
 20128	
 20129	  /* Вывод всей таблицы процессов ядра, чтобы получить регистры. */
 20130	  trace_off = 0;
 20131	  while (sys_trace(T_GETUSER, slot, trace_off, &trace_data) == OK) {
 20132	        if (write(fd, (char *) &trace_data, (unsigned) sizeof (long))
 20133	            != (unsigned) sizeof (long)) {
 20134	                close(fd);
 20135	                return;
 20136	        }
 20137	        trace_off += sizeof (long);
 20138	  }
 20139	
 20140	  /* Цикл по сегментам и вывод самих сегментов. */
 20141	  for (seg = 0; seg < NR_LOCAL_SEGS; seg++) {
 20142	        rw_seg(1, fd, slot, seg,
 20143	                (phys_bytes) rmp->mp_seg[seg].mem_len << CLICK_SHIFT);
 20144	  }
 20145	  close(fd);
 20146	}
	

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/timers.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 20200	/* Управление сторожевыми таймерами менеджера процессов. Функции этого файла
 20201	 * обеспечивают удобный интерфейс с библиотекой таймеров, управляющей списком
 20202	 * сторожевых таймеров. Этот интерфейс скрывает все детали планирования
 20203	 * оповещения заданием CLOCK. Только системным процессам разрешено
 20204	 * устанавливать таймер оповещения в ядре. По этой причине менеджер
 20205	 * процессов поддерживает локальный список таймеров для пользовательских
 20206	 * процессов, пославших запрос на сигнал оповещения. 
 20207	 * 
 20208	 * Данный файл имеет следующие точки входа: 
 20209	 *   pm_set_timer:       сброс существующего или установка нового сторожевого таймера
 20210	 *   pm_expire_timers:   проверка истекших таймеров и запуск сторожевых функций
 20211	 *   pm_cancel_timer:    удаление таймера из списка таймеров
 20212	 *
 20213	 */
 20214	
 20215	#include "pm.h"
 20216	
 20217	#include <timers.h>
 20218	#include <minix/syslib.h>
 20219	#include <minix/com.h>
 20220	
 20221	PRIVATE timer_t *pm_timers = NULL;
 20222	
 20223	/*===========================================================================*
 20224	 *                              pm_set_timer                                 *
 20225	 *===========================================================================*/
 20226	PUBLIC void pm_set_timer(timer_t *tp, int ticks, tmr_func_t watchdog, int arg)
 20227	{
 20228	        int r;
 20229	        clock_t now, prev_time = 0, next_time;
 20230	
 20231	        if ((r = getuptime(&now)) != OK)
 20232	                panic(__FILE__, "PM couldn't get uptime", NO_NUM);
 20233	
 20234	        /* Установка аргумента таймера и добавление таймера в список. */
 20235	        tmr_arg(tp)->ta_int = arg;
 20236	        prev_time = tmrs_settimer(&pm_timers,tp,now+ticks,watchdog,&next_time);
 20237	
 20238	        /* Перепланирование синхронного оповещения при необходимости. */
 20239	        if (! prev_time || prev_time > next_time) {
 20240	                if (sys_setalarm(next_time, 1) != OK)
 20241	                        panic(__FILE__, "PM set timer couldn't set alarm.", NO_NUM);
 20242	        }
 20243	
 20244	        return;
 20245	}
	
 20247	/*===========================================================================*
 20248	 *                              pm_expire_timers                             *
 20249	 *===========================================================================*/
 20250	PUBLIC void pm_expire_timers(clock_t now)
 20251	{
 20252	        clock_t next_time;
 20253	
 20254	        /* Проверка истекших таймеров и, возможно, перепланирование оповещения. */
 20255	        tmrs_exptimers(&pm_timers, now, &next_time);
 20256	        if (next_time > 0) {
 20257	                if (sys_setalarm(next_time, 1) != OK)
 20258	                        panic(__FILE__, "PM expire timer couldn't set alarm.", NO_NUM);
 20259	        }
 20260	}
	
 20262	/*===========================================================================*
 20263	 *                              pm_cancel_timer                              *
 20264	 *===========================================================================*/
 20265	PUBLIC void pm_cancel_timer(timer_t *tp)
 20266	{
 20267	        clock_t next_time, prev_time;
 20268	        prev_time = tmrs_clrtimer(&pm_timers, tp, &next_time);
 20269	
 20270	        /* При удалении ближайшего таймера необходимо перевести оповещение на следующий 
 20271	     * таймер либо вообще отменить оповещение, если отмененным оказался последний таймер 
 20272	     * (в этом случае next_time будет иметь значение 0).
 20273	         */
 20274	        if (prev_time < next_time || ! next_time) {
 20275	                if (sys_setalarm(next_time, 1) != OK)
 20276	                        panic(__FILE__, "PM expire timer couldn't set alarm.", NO_NUM);
 20277	        }
 20278	}


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/time.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 20300	/* Этот файл обрабатывает системные вызовы, связанные со временем.
 20301	 *
 20302	 * Файл имеет следующие точки входа:
 20303	 *   do_time:            выполнение системного вызова TIME
 20304	 *   do_stime:           выполнение системного вызова STIME
 20305	 *   do_times:           выполнение системного вызова TIMES
 20306	 */
 20307	
 20308	#include "pm.h"
 20309	#include <minix/callnr.h>
 20310	#include <minix/com.h>
 20311	#include <signal.h>
 20312	#include "mproc.h"
 20313	#include "param.h"
 20314	
 20315	PRIVATE time_t boottime;
 20316	
 20317	/*===========================================================================*
 20318	 *                              do_time                                      *
 20319	 *===========================================================================*/
 20320	PUBLIC int do_time()
 20321	{
 20322	/* Выполнение системного вызова time(tp). Он возвращает время в секундах, прошедшее с
 20323	 * 1 января 1970 г.  MINIX - астрофизически наивная система, считающая, что Земля 
 20324	 * вращается с постоянной скоростью и теряемых секунд не существует.
 20325	 *
 20326	 */
 20327	  clock_t uptime;
 20328	  int s;
 20329	
 20330	  if ( (s=getuptime(&uptime)) != OK) 
 20331	        panic(__FILE__,"do_time couldn't get uptime", s);
 20332	
 20333	  mp->mp_reply.reply_time = (time_t) (boottime + (uptime/HZ));
 20334	  mp->mp_reply.reply_utime = (uptime%HZ)*1000000/HZ;
 20335	  return(OK);
 20336	}
	
 20338	/*===========================================================================*
 20339	 *                              do_stime                                     *
 20340	 *===========================================================================*/
 20341	PUBLIC int do_stime()
 20342	{
 20343	/* Выполнение системного вызова stime(tp). Получение времени работы системы (число 
 20344	 * тактов с момента загрузки) и сохранение времени в секундах во время загрузки системы
 20345	 * в глобальной переменной 'boottime'.
 20346	 */
 20347	  clock_t uptime;
 20348	  int s;
 20349	
 20350	  if (mp->mp_effuid != SUPER_USER) { 
 20351	      return(EPERM);
 20352	  }
 20353	  if ( (s=getuptime(&uptime)) != OK) 
 20354	      panic(__FILE__,"do_stime couldn't get uptime", s);
 20355	  boottime = (long) m_in.stime - (uptime/HZ);
 20356	
 20357	  /* Информирование файловой системы о новом системном времени. */
 20358	  tell_fs(STIME, boottime, 0, 0);
 20359	
 20360	  return(OK);
 20361	}
	
 20363	/*===========================================================================*
 20364	 *                              do_times                                     *
 20365	 *===========================================================================*/
 20366	PUBLIC int do_times()
 20367	{
 20368	/* Выполнение системного вызова times(buffer). */
 20369	  register struct mproc *rmp = mp;
 20370	  clock_t t[5];
 20371	  int s;
 20372	
 20373	  if (OK != (s=sys_times(who, t)))
 20374	      panic(__FILE__,"do_times couldn't get times", s);
 20375	  rmp->mp_reply.reply_t1 = t[0];                /* пользовательское время */
 20376	  rmp->mp_reply.reply_t2 = t[1];                /* системное время */
 20377	  rmp->mp_reply.reply_t3 = rmp->mp_child_utime; /* пользовательское время дочернего процесса */
 20378	  rmp->mp_reply.reply_t4 = rmp->mp_child_stime; /* системное время дочернего процесса */
 20379	  rmp->mp_reply.reply_t5 = t[4];                /* время работы системы, считая с загрузки */
 20380	
 20381	  return(OK);
 20382	}
	

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/getset.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 20400	/* Этот файл обрабатывает 4 системных вызова, получающих и устанавливающих uid и gid.
 20401	 * Он также обрабатывает функции getpid(), setsid() и getpgrp(). Код каждой из них так мал, что
 20402	 * что едва ли имело смысл разбивать его на отдельные функции.
 20403	 * 
 20404	 */
 20405	
 20406	#include "pm.h"
 20407	#include <minix/callnr.h>
 20408	#include <signal.h>
 20409	#include "mproc.h"
 20410	#include "param.h"
 20411	
 20412	/*===========================================================================*
 20413	 *                              do_getset                                    *
 20414	 *===========================================================================*/
 20415	PUBLIC int do_getset()
 20416	{
 20417	/* Обработка GETUID, GETGID, GETPID, GETPGRP, SETUID, SETGID и SETSID.  Четыре
 20418	 * GET и SETSID возвращают свои основные результаты в 'r'. GETUID, GETGID и
 20419	 * GETPID также возвращают дополнительные результаты (эффективные идентификаторы или
 20420	 * идентификаторы родительских процессов) в 'reply_res2' – они возвращаются пользователю.
 20421	 */
 20422	
 20423	  register struct mproc *rmp = mp;
 20424	  register int r;
 20425	
 20426	  switch(call_nr) {
 20427	        case GETUID: 
 20428	                r = rmp->mp_realuid;
 20429	                rmp->mp_reply.reply_res2 = rmp->mp_effuid;
 20430	                break;
 20431	
 20432	        case GETGID: 
 20433	                r = rmp->mp_realgid;
 20434	                rmp->mp_reply.reply_res2 = rmp->mp_effgid;
 20435	                break;
 20436	
 20437	        case GETPID: 
 20438	                r = mproc[who].mp_pid;
 20439	                rmp->mp_reply.reply_res2 = mproc[rmp->mp_parent].mp_pid;
 20440	                break;
 20441	
 20442	        case SETUID: 
 20443	                if (rmp->mp_realuid != (uid_t) m_in.usr_id && 
 20444	                                rmp->mp_effuid != SUPER_USER)
 20445	                        return(EPERM);
 20446	                rmp->mp_realuid = (uid_t) m_in.usr_id;
 20447	                rmp->mp_effuid = (uid_t) m_in.usr_id;
 20448	                tell_fs(SETUID, who, rmp->mp_realuid, rmp->mp_effuid);
 20449	                r = OK;
 20450	                break;
 20451	
 20452	        case SETGID: 
 20453	                if (rmp->mp_realgid != (gid_t) m_in.grp_id && 
 20454	                                rmp->mp_effuid != SUPER_USER)
 20455	                        return(EPERM);
 20456	                rmp->mp_realgid = (gid_t) m_in.grp_id;
 20457	                rmp->mp_effgid = (gid_t) m_in.grp_id;
 20458	                tell_fs(SETGID, who, rmp->mp_realgid, rmp->mp_effgid);
 20459	                r = OK;
 20460	                break;
 20461	
 20462	        case SETSID: 
 20463	                if (rmp->mp_procgrp == rmp->mp_pid) return(EPERM);
 20464	                rmp->mp_procgrp = rmp->mp_pid;
 20465	                tell_fs(SETSID, who, 0, 0);
 20466	                /* дальше */
 20467	
 20468	        case GETPGRP: 
 20469	                r = rmp->mp_procgrp;
 20470	                break;
 20471	
 20472	        default: 
 20473	                r = EINVAL;
 20474	                break;  
 20475	  }
 20476	  return(r);
 20477	}



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/pm/misc.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 20500	/* Различные системные вызовы.                          Author:  Kees J. Bot
 20501	 *                                                              31 марта 2000
 20502	 * Файл имеет следующие точки входа: 
 20503	 *   do_reboot:         уничтожить все процессы, затем перезагрузить систему
 20504	 *   do_svrctl:         контроль менеджера процессов
 20505	 *   do_getsysinfo:     запрос копии структуры данных менеджера процессов (Jorrit N. Herder)
 20506	 *   do_getprocnr:      поиск процесса по номеру записи (Jorrit N. Herder)
 20507	 *   do_memalloc:       выделение области памяти (Jorrit N. Herder)
 20508	 *   do_memfree:        освобождение области памяти (Jorrit N. Herder)
 20509	 *   do_getsetpriority: получение/установка приоритета процесса
 20510	 */
 20511	
 20512	#include "pm.h"
 20513	#include <minix/callnr.h>
 20514	#include <signal.h>
 20515	#include <sys/svrctl.h>
 20516	#include <sys/resource.h>
 20517	#include <minix/com.h>
 20518	#include <string.h>
 20519	#include "mproc.h"
 20520	#include "param.h"
 20521	
 20522	/*===========================================================================*
 20523	 *                              do_allocmem                                  *
 20524	 *===========================================================================*/
 20525	PUBLIC int do_allocmem()
 20526	{
 20527	  vir_clicks mem_clicks;
 20528	  phys_clicks mem_base;
 20529	
 20530	  mem_clicks = (m_in.memsize + CLICK_SIZE -1 ) >> CLICK_SHIFT;
 20531	  mem_base = alloc_mem(mem_clicks);
 20532	  if (mem_base == NO_MEM) return(ENOMEM);
 20533	  mp->mp_reply.membase =  (phys_bytes) (mem_base << CLICK_SHIFT);
 20534	  return(OK);
 20535	}
	
 20537	/*===========================================================================*
 20538	 *                              do_freemem                                   *
 20539	 *===========================================================================*/
 20540	PUBLIC int do_freemem()
 20541	{
 20542	  vir_clicks mem_clicks;
 20543	  phys_clicks mem_base;
 20544	
 20545	  mem_clicks = (m_in.memsize + CLICK_SIZE -1 ) >> CLICK_SHIFT;
 20546	  mem_base = (m_in.membase + CLICK_SIZE -1 ) >> CLICK_SHIFT;
 20547	  free_mem(mem_base, mem_clicks);
 20548	  return(OK);
 20549	}
	
 20551	/*===========================================================================*
 20552	 *                              do_getsysinfo                                *
 20553	 *===========================================================================*/
 20554	PUBLIC int do_getsysinfo()
 20555	{
 20556	  struct mproc *proc_addr;
 20557	  vir_bytes src_addr, dst_addr;
 20558	  struct kinfo kinfo;
 20559	  size_t len;
 20560	  int s;
 20561	
 20562	  switch(m_in.info_what) {
 20563	  case SI_KINFO:                         /* получение информации ядра через менеджер процессов */
 20564	        sys_getkinfo(&kinfo);
 20565	        src_addr = (vir_bytes) &kinfo;
 20566	        len = sizeof(struct kinfo);
 20567	        break;
 20568	  case SI_PROC_ADDR:                     /* получение адреса таблицы процессов менеджера процессов */
 20569	        proc_addr = &mproc[0];
 20570	        src_addr = (vir_bytes) &proc_addr;
 20571	        len = sizeof(struct mproc *);
 20572	        break; 
 20573	  case SI_PROC_TAB:                      /* копирование таблицы процессов целиком */
 20574	        src_addr = (vir_bytes) mproc;
 20575	        len = sizeof(struct mproc) * NR_PROCS;
 20576	        break;
 20577	  default: 
 20578	        return(EINVAL);
 20579	  }
 20580	
 20581	  dst_addr = (vir_bytes) m_in.info_where;
 20582	  if (OK != (s=sys_datacopy(SELF, src_addr, who, dst_addr, len)))
 20583	        return(s);
 20584	  return(OK);
 20585	}
	
 20587	/*===========================================================================*
 20588	 *                              do_getprocnr                                 *
 20589	 *===========================================================================*/
 20590	PUBLIC int do_getprocnr()
 20591	{
 20592	  register struct mproc *rmp;
 20593	  static char search_key[PROC_NAME_LEN+1];
 20594	  int key_len;
 20595	  int s;
 20596	
 20597	  if (m_in.pid >= 0) {                          /* поиск процесса по pid */
 20598	        for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
 20599	                if ((rmp->mp_flags & IN_USE) && (rmp->mp_pid==m_in.pid)) {
 20600	                        mp->mp_reply.procnr = (int) (rmp - mproc);
 20601	                        return(OK);
 20602	                } 
 20603	        }
 20604	        return(ESRCH);                  
 20605	  } else if (m_in.namelen > 0) {                /* поиск процесса по имени */
 20606	        key_len = MIN(m_in.namelen, PROC_NAME_LEN);
 20607	        if (OK != (s=sys_datacopy(who, (vir_bytes) m_in.addr, 
 20608	                        SELF, (vir_bytes) search_key, key_len))) 
 20609	                return(s);
 20610	        search_key[key_len] = '\0';     /* terminate for safety */
 20611	        for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) {
 20612	                if ((rmp->mp_flags & IN_USE) && 
 20613	                        strncmp(rmp->mp_name, search_key, key_len)==0) {
 20614	                        mp->mp_reply.procnr = (int) (rmp - mproc);
 20615	                        return(OK);
 20616	                } 
 20617	        }
 20618	        return(ESRCH);                  
 20619	  } else {                              /* возврат собственного номера процесса */
 20620	        mp->mp_reply.procnr = who;
 20621	  }
 20622	  return(OK);
 20623	}
	
 20625	/*===========================================================================*
 20626	 *                              do_reboot                                    *
 20627	 *===========================================================================*/
 20628	#define REBOOT_CODE     "delay; boot"
 20629	PUBLIC int do_reboot()
 20630	{
 20631	  char monitor_code[32*sizeof(char *)];         
 20632	  int code_len;
 20633	  int abort_flag;
 20634	
 20635	  if (mp->mp_effuid != SUPER_USER) return(EPERM);
 20636	
 20637	  switch (m_in.reboot_flag) {
 20638	  case RBT_HALT: 
 20639	  case RBT_PANIC: 
 20640	  case RBT_RESET: 
 20641	        abort_flag = m_in.reboot_flag;
 20642	        break;
 20643	  case RBT_REBOOT: 
 20644	        code_len = strlen(REBOOT_CODE) + 1;
 20645	        strncpy(monitor_code, REBOOT_CODE, code_len);        
 20646	        abort_flag = RBT_MONITOR;
 20647	        break;
 20648	  case RBT_MONITOR: 
 20649	        code_len = m_in.reboot_strlen + 1;
 20650	        if (code_len > sizeof(monitor_code)) return(EINVAL);
 20651	        if (sys_datacopy(who, (vir_bytes) m_in.reboot_code,
 20652	                PM_PROC_NR, (vir_bytes) monitor_code,
 20653	                (phys_bytes) (code_len)) != OK) return(EFAULT);
 20654	        if (monitor_code[code_len-1] != 0) return(EINVAL);
 20655	        abort_flag = RBT_MONITOR;
 20656	        break;
 20657	  default: 
 20658	        return(EINVAL);
 20659	  }
 20660	
 20661	  check_sig(-1, SIGKILL);               /* уничтожить все процессы, кроме init */
 20662	  tell_fs(REBOOT,0,0,0);                /* указание файловой системе подготовиться к завершению */
 20663	
 20664	  /* Обращение к ядру с целью завершить работу. Все системные службы, включая менеджер процессов,
 20665	   * получают уведомление HARD_STOP. Ожидание уведомления в главном цикле.
 20666	   */
 20667	  sys_abort(abort_flag, PM_PROC_NR, monitor_code, code_len);
 20668	  return(SUSPEND);                      /* не отвечать уничтоженному процессу */
 20669	}
	
 20671	/*===========================================================================*
 20672	 *                              do_getsetpriority                            *
 20673	 *===========================================================================*/
 20674	PUBLIC int do_getsetpriority()
 20675	{
 20676	        int arg_which, arg_who, arg_pri;
 20677	        int rmp_nr;
 20678	        struct mproc *rmp;
 20679	
 20680	        arg_which = m_in.m1_i1;
 20681	        arg_who = m_in.m1_i2;
 20682	        arg_pri = m_in.m1_i3;   /* для SETPRIORITY */
 20683	
 20684	        /* Код, общий для GETPRIORITY и SETPRIORITY. */
 20685	
 20686	        /* Поддержка только PRIO_PROCESS. */
 20687	        if (arg_which != PRIO_PROCESS)
 20688	                return(EINVAL);
 20689	
 20690	        if (arg_who == 0)
 20691	                rmp_nr = who;
 20692	        else
 20693	                if ((rmp_nr = proc_from_pid(arg_who)) < 0)
 20694	                        return(ESRCH);
 20695	
 20696	        rmp = &mproc[rmp_nr];
 20697	
 20698	        if (mp->mp_effuid != SUPER_USER &&
 20699	           mp->mp_effuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_realuid)
 20700	                return EPERM;
 20701	
 20702	        /* Если GET, все. */
 20703	        if (call_nr == GETPRIORITY) {
 20704	                return(rmp->mp_nice - PRIO_MIN);
 20705	        }
 20706	
 20707	        /* Только root может снижать уровень вежливости. */
 20708	        if (rmp->mp_nice > arg_pri && mp->mp_effuid != SUPER_USER)
 20709	                return(EACCES);
 20710	        
 20711	        /* Разрешенный SET. Выполнить и информировать ядро. */
 20712	        rmp->mp_nice = arg_pri;
 20713	        return sys_nice(rmp_nr, arg_pri);
 20714	}
	
 20716	/*===========================================================================*
 20717	 *                              do_svrctl                                    *
 20718	 *===========================================================================*/
 20719	PUBLIC int do_svrctl()
 20720	{
 20721	  int s, req;
 20722	  vir_bytes ptr;
 20723	#define MAX_LOCAL_PARAMS 2
 20724	  static struct {
 20725	        char name[30];
 20726	        char value[30];
 20727	  } local_param_overrides[MAX_LOCAL_PARAMS];
 20728	  static int local_params = 0;
 20729	
 20730	  req = m_in.svrctl_req;
 20731	  ptr = (vir_bytes) m_in.svrctl_argp;
 20732	
 20733	  /* Предназначен ли вызов менеджеру процессов? */
 20734	  if (((req >> 8) & 0xFF) != 'M') return(EINVAL);
 20735	
 20736	  /* Локальные операции управления менеджера процессов. */
 20737	  switch(req) {
 20738	  case MMSETPARAM: 
 20739	  case MMGETPARAM:  {
 20740	      struct sysgetenv sysgetenv;
 20741	      char search_key[64];
 20742	      char *val_start;
 20743	      size_t val_len;
 20744	      size_t copy_len;
 20745	
 20746	      /* Копирование структуры sysgetenv в менеджер процессов. */
 20747	      if (sys_datacopy(who, ptr, SELF, (vir_bytes) &sysgetenv, 
 20748	              sizeof(sysgetenv)) != OK) return(EFAULT);  
 20749	
 20750	      /* перегрузка параметров? */
 20751	      if (req == MMSETPARAM) {
 20752	        if (local_params >= MAX_LOCAL_PARAMS) return ENOSPC;
 20753	        if (sysgetenv.keylen <= 0
 20754	         || sysgetenv.keylen >=
 20755	                 sizeof(local_param_overrides[local_params].name)
 20756	         || sysgetenv.vallen <= 0
 20757	         || sysgetenv.vallen >=
 20758	                 sizeof(local_param_overrides[local_params].value))
 20759	                return EINVAL;
 20760	                
 20761	          if ((s = sys_datacopy(who, (vir_bytes) sysgetenv.key,
 20762	            SELF, (vir_bytes) local_param_overrides[local_params].name,
 20763	               sysgetenv.keylen)) != OK)
 20764	                return s;
 20765	          if ((s = sys_datacopy(who, (vir_bytes) sysgetenv.val,
 20766	            SELF, (vir_bytes) local_param_overrides[local_params].value,
 20767	              sysgetenv.keylen)) != OK)
 20768	                return s;
 20769	            local_param_overrides[local_params].name[sysgetenv.keylen] = '\0';
 20770	            local_param_overrides[local_params].value[sysgetenv.vallen] = '\0';
 20771	
 20772	        local_params++;
 20773	
 20774	        return OK;
 20775	      }
 20776	
 20777	      if (sysgetenv.keylen == 0) {      /* копирование всех параметров */
 20778	          val_start = monitor_params;
 20779	          val_len = sizeof(monitor_params);
 20780	      } 
 20781	      else {                            /* поиск значения по ключу */
 20782	          int p;
 20783	          /* Попытка получить копию запрошенного ключа. */
 20784	          if (sysgetenv.keylen > sizeof(search_key)) return(EINVAL);
 20785	          if ((s = sys_datacopy(who, (vir_bytes) sysgetenv.key,
 20786	                  SELF, (vir_bytes) search_key, sysgetenv.keylen)) != OK)
 20787	              return(s);
 20788	
 20789	          /* Проверка наличиня null-символа на конце ключа и поиск значения.
 20790	           * Сначала проверка локальных переопределений.
 20791	           */
 20792	          search_key[sysgetenv.keylen-1]= '\0';
 20793	          for(p = 0; p < local_params; p++) {
 20794	                if (!strcmp(search_key, local_param_overrides[p].name)) {
 20795	                        val_start = local_param_overrides[p].value;
 20796	                        break;
 20797	                }
 20798	          }
 20799	          if (p >= local_params && (val_start = find_param(search_key)) == NULL)
 20800	               return(ESRCH);
 20801	          val_len = strlen(val_start) + 1;
 20802	      }
 20803	
 20804	      /* Проверка вместимости в буфер клиента. */
 20805	      if (val_len > sysgetenv.vallen)
 20806	        return E2BIG;
 20807	
 20808	      /* Значение найдено, создать фактическую копию (максимально быстро). */
 20809	      copy_len = MIN(val_len, sysgetenv.vallen); 
 20810	      if ((s=sys_datacopy(SELF, (vir_bytes) val_start, 
 20811	              who, (vir_bytes) sysgetenv.val, copy_len)) != OK)
 20812	          return(s);
 20813	
 20814	      return OK;
 20815	  }
 20816	  default: 
 20817	        return(EINVAL);
 20818	  }
 20819	}
   
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/fs.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 20900	/* Основной заголовочный файл файловой системы. Он включает некоторые другие файлы
 20901	 * и определяет основные константы.
 20902	 */
 20903	#define _POSIX_SOURCE      1    /* заголовочные файлы включать содержимое POSIX */
 20904	#define _MINIX             1    /* заголовочные файлы должны включать содержимое для MINIX */
 20905	#define _SYSTEM            1    /* указать заголовочным файлам на то, что это ядро */
 20906	
 20907	#define VERBOSE            0    /* показывать сообщения в процессе инициализации? */
 20908	
 20909	/* Следующие заголовочные файлы включаются в файлы *.c автоматически. */
 20910	#include <minix/config.h>       /* ДОЛЖЕН быть первым */
 20911	#include <ansi.h>               /* ДОЛЖЕН быть вторым */
 20912	#include <sys/types.h>
 20913	#include <minix/const.h>
 20914	#include <minix/type.h>
 20915	#include <minix/dmap.h>
 20916	
 20917	#include <limits.h>
 20918	#include <errno.h>
 20919	
 20920	#include <minix/syslib.h>
 20921	#include <minix/sysutil.h>
 20922	
 20923	#include "const.h"
 20924	#include "type.h"
 20925	#include "proto.h"
 20926	#include "glo.h"




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/const.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 21000	/* Размеры таблиц */
 21001	#define V1_NR_DZONES       7    /* число номеров прямых зон в индексном узле V1 */
 21002	#define V1_NR_TZONES       9    /* общее число номеров зон в индексном узле V1 */
 21003	#define V2_NR_DZONES       7    /* число номеров прямых зон в индексном узле V2 */
 21004	#define V2_NR_TZONES      10    /* общее число номеров зон в индексном узле V2 */
 21005	
 21006	#define NR_FILPS         128    /* число записей в таблице filp */
 21007	#define NR_INODES         64    /* число записей в таблице "внутри" индексных узлов */
 21008	#define NR_SUPERS          8    /* число записей в таблице суперблоков  */
 21009	#define NR_LOCKS           8    /* число записей в таблице блокирования файлов */
 21010	
 21011	/* Тип sizeof может быть (unsigned) long. Используйте следующий макрос для определения
 21012	 * размеров небольших объектов, чтобы избежать сюрпризов, например, передачи констант
 21013	 * long в функции, принимающие int.
 21014	 */
 21015	#define usizeof(t) ((unsigned) sizeof(t))
 21016	
 21017	/* Типы файловой системы. */
 21018	#define SUPER_MAGIC   0x137F    /* магическое число в суперблоке */
 21019	#define SUPER_REV     0x7F13    /* магическое число, когда диск 68000 читается на PC или vv */
 21020	#define SUPER_V2      0x2468    /* магическое число для файловой системы V2 */
 21021	#define SUPER_V2_REV  0x6824    /* магическое число V2, записываемое PC и считываемое на 68000 или vv */
 21022	#define SUPER_V3      0x4d5a    /* магическое число для файловой системы V3 */
 21023	
 21024	#define V1                 1    /* номер версии файловой системы V1 */ 
 21025	#define V2                 2    /* номер версии файловой системы V2 */ 
 21026	#define V3                 3    /* номер версии файловой системы V3 */ 
 21027	
 21028	/* Различные константы */
 21029	#define SU_UID   ((uid_t) 0)    /* uid_t суперпользователя */
 21030	#define SYS_UID  ((uid_t) 0)    /* uid_t для менеджера процессов MM и INIT */
 21031	#define SYS_GID  ((gid_t) 0)    /* gid_t для менеджера процессов MM и INIT */
 21032	#define NORMAL             0    /* принуждает get_block выполнить считывание с диска */
 21033	#define NO_READ            1    /* предотвращает считывание с диска get_block */
 21034	#define PREFETCH           2    /* указывает get_block не читать и не помечать устройство */
 21035	
 21036	#define XPIPE   (-NR_TASKS-1)   /* используется в fp_task при приостановке на канале */
 21037	#define XLOCK   (-NR_TASKS-2)   /* используется в fp_task при приостановке на блокировании */
 21038	#define XPOPEN  (-NR_TASKS-3)   /* используется в fp_task при приостановке на открытии канала */
 21039	#define XSELECT (-NR_TASKS-4)   /* используется в fp_task при приостановке на выборе */
 21040	
 21041	#define NO_BIT   ((bit_t) 0)    /* возвращается alloc_bit() для указания ошибки */
 21042	
 21043	#define DUP_MASK        0100    /* маска для различения dup2 и dup */
 21044	
 21045	#define LOOK_UP            0 /* указывает search_dir выполнить поиск строки */
 21046	#define ENTER              1 /* указывает search_dir создать запись каталога */
 21047	#define DELETE             2 /* указывает search_dir удалить запись */
 21048	#define IS_EMPTY           3 /* указывает search_dir возвратить OK или ENOTEMPTY */  
 21049	
 21050	#define CLEAN              0    /* копии на диске и в памяти идентичны */
 21051	#define DIRTY              1    /* копии на диске и в памяти различаются */
 21052	#define ATIME            002    /* устанавливается, если необходимо обновить поле atime */
 21053	#define CTIME            004    /* устанавливается, если необходимо обновить поле ctime */
 21054	#define MTIME            010    /* устанавливается, если необходимо обновить поле mtime */
 21055	
 21056	#define BYTE_SWAP          0    /* указывает conv2/conv4 переставить байты */
 21057	
 21058	#define END_OF_FILE   (-104)    /* обнаружен конец файла*/
 21059	
 21060	#define ROOT_INODE         1            /* номер индексного узла корневого каталога */
 21061	#define BOOT_BLOCK  ((block_t) 0)       /* номер загрузочного блока */
 21062	#define SUPER_BLOCK_BYTES (1024)        /* байтовое смещение */
 21063	#define START_BLOCK     2               /* первый блок файловой системы (не считая суперблока) */
 21064	
 21065	#define DIR_ENTRY_SIZE       usizeof (struct direct)   /* число байтовна запись каталога   */
 21066	#define NR_DIR_ENTRIES(b)   ((b)/DIR_ENTRY_SIZE)       /* число записей каталогов на блок   */
 21067	#define SUPER_SIZE      usizeof (struct super_block)   /* размер суперблока    */
 21068	#define PIPE_SIZE(b)          (V1_NR_DZONES*(b))       /* размер канала в байтах  */
 21069	
 21070	#define FS_BITMAP_CHUNKS(b) ((b)/usizeof (bitchunk_t)) /* число областей карты на блок   */
 21071	#define FS_BITCHUNK_BITS                (usizeof(bitchunk_t) * CHAR_BIT)
 21072	#define FS_BITS_PER_BLOCK(b)    (FS_BITMAP_CHUNKS(b) * FS_BITCHUNK_BITS)
 21073	
 21074	/* Размеры, относящиеся к файловой системе V1. */
 21075	#define V1_ZONE_NUM_SIZE           usizeof (zone1_t)  /* число байтов в зоне V1 */
 21076	#define V1_INODE_SIZE             usizeof (d1_inode)  /* байтов в индексном узле V1 */
 21077	
 21078	/* число зон на косвенный блок */
 21079	#define V1_INDIRECTS (STATIC_BLOCK_SIZE/V1_ZONE_NUM_SIZE)  
 21080	
 21081	/* число индексных узлов V1 на блок */
 21082	#define V1_INODES_PER_BLOCK (STATIC_BLOCK_SIZE/V1_INODE_SIZE)
 21083	
 21084	/* Размеры, относящиеся к файловой системе V2. */
 21085	#define V2_ZONE_NUM_SIZE            usizeof (zone_t)  /* число байтов в зоне V2 */
 21086	#define V2_INODE_SIZE             usizeof (d2_inode)  /* байтов в индексном узле V2 */
 21087	#define V2_INDIRECTS(b)   ((b)/V2_ZONE_NUM_SIZE)      /* число зон на косвенный блок */
 21088	#define V2_INODES_PER_BLOCK(b) ((b)/V2_INODE_SIZE)    /* число индексных узлов V2 на блок */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/type.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 21100	/* Объявление индексного узла V1 в виде, в котором он находится на диске (не внутри). */
 21101	typedef struct {                /* индексный узел V1.x */
 21102	  mode_t d1_mode;               /* тип файла, защита и т. д. */
 21103	  uid_t d1_uid;                 /* идентификатор пользователя - владельца файла */
 21104	  off_t d1_size;                /* текущий размер файла в байтах */
 21105	  time_t d1_mtime;              /* время последнего изменения данных файла */
 21106	  u8_t d1_gid;                  /* номер группы */
 21107	  u8_t d1_nlinks;               /* число связей файла */
 21108	  u16_t d1_zone[V1_NR_TZONES];  /* номера блоков для прямой, косвенной и дважды косвенной зоны */
 21109	} d1_inode;
 21110	
 21111	/* Объявление индексного узла V2 в виде, в котором он находится на диске (не внутри). */
 21112	typedef struct {                /* индексный узел V2.x */
 21113	  mode_t d2_mode;               /* тип файла, защита и т. д. */
 21114	  u16_t d2_nlinks;              /* число связей файла. ТРЮК! */
 21115	  uid_t d2_uid;                 /* идентификатор пользователя - владельца файла. */
 21116	  u16_t d2_gid;                 /* номер группы HACK! */
 21117	  off_t d2_size;                /* текущий размер файла в байтах */
 21118	  time_t d2_atime;              /* время последнего доступа к данным файла */
 21119	  time_t d2_mtime;              /* время последнего изменения данных файла */
 21120	  time_t d2_ctime;              /* время последнего изменения данных индексного узла */
 21121	  zone_t d2_zone[V2_NR_TZONES]; /* номера блоков для прямой, косвенной и дважды косвенной зоны */
 21122	} d2_inode;



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/proto.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 21200	/* Прототипы функций. */
 21201	
 21202	#include "timers.h"
 21203	
 21204	/* Сначала должны быть объявлены структуры, используемые в прототипах. */
 21205	struct buf;
 21206	struct filp;            
 21207	struct inode;
 21208	struct super_block;
 21209	
 21210	/* cache.c */
 21211	_PROTOTYPE( zone_t alloc_zone, (Dev_t dev, zone_t z)                    );
 21212	_PROTOTYPE( void flushall, (Dev_t dev)                                  );
 21213	_PROTOTYPE( void free_zone, (Dev_t dev, zone_t numb)                    );
 21214	_PROTOTYPE( struct buf *get_block, (Dev_t dev, block_t block,int only_search));
 21215	_PROTOTYPE( void invalidate, (Dev_t device)                             );
 21216	_PROTOTYPE( void put_block, (struct buf *bp, int block_type)            );
 21217	_PROTOTYPE( void rw_block, (struct buf *bp, int rw_flag)                );
 21218	_PROTOTYPE( void rw_scattered, (Dev_t dev,
 21219	                        struct buf **bufq, int bufqsize, int rw_flag)   );
 21220	
 21221	/* device.c */
 21222	_PROTOTYPE( int dev_open, (Dev_t dev, int proc, int flags)              );
 21223	_PROTOTYPE( void dev_close, (Dev_t dev)                                 );
 21224	_PROTOTYPE( int dev_io, (int op, Dev_t dev, int proc, void *buf,
 21225	                        off_t pos, int bytes, int flags)                );
 21226	_PROTOTYPE( int gen_opcl, (int op, Dev_t dev, int proc, int flags)      );
 21227	_PROTOTYPE( void gen_io, (int task_nr, message *mess_ptr)               );
 21228	_PROTOTYPE( int no_dev, (int op, Dev_t dev, int proc, int flags)        );
 21229	_PROTOTYPE( int tty_opcl, (int op, Dev_t dev, int proc, int flags)      );
 21230	_PROTOTYPE( int ctty_opcl, (int op, Dev_t dev, int proc, int flags)     );
 21231	_PROTOTYPE( int clone_opcl, (int op, Dev_t dev, int proc, int flags)    );
 21232	_PROTOTYPE( void ctty_io, (int task_nr, message *mess_ptr)              );
 21233	_PROTOTYPE( int do_ioctl, (void)                                        );
 21234	_PROTOTYPE( int do_setsid, (void)                                       );
 21235	_PROTOTYPE( void dev_status, (message *)                                );
 21236	
 21237	/* dmp.c */
 21238	_PROTOTYPE( int do_fkey_pressed, (void)                                 );
 21239	
 21240	/* dmap.c */
 21241	_PROTOTYPE( int do_devctl, (void)                                       );
 21242	_PROTOTYPE( void build_dmap, (void)                                     );
 21243	_PROTOTYPE( int map_driver, (int major, int proc_nr, int dev_style)     );
 21244	
 21245	/* filedes.c */
 21246	_PROTOTYPE( struct filp *find_filp, (struct inode *rip, mode_t bits)    );
 21247	_PROTOTYPE( int get_fd, (int start, mode_t bits, int *k, struct filp **fpt) );
 21248	_PROTOTYPE( struct filp *get_filp, (int fild)                           );
 21249	
 21250	/* inode.c */
 21251	_PROTOTYPE( struct inode *alloc_inode, (dev_t dev, mode_t bits)         );
 21252	_PROTOTYPE( void dup_inode, (struct inode *ip)                          );
 21253	_PROTOTYPE( void free_inode, (Dev_t dev, Ino_t numb)                    );
 21254	_PROTOTYPE( struct inode *get_inode, (Dev_t dev, int numb)              );
 21255	_PROTOTYPE( void put_inode, (struct inode *rip)                         );
 21256	_PROTOTYPE( void update_times, (struct inode *rip)                      );
 21257	_PROTOTYPE( void rw_inode, (struct inode *rip, int rw_flag)             );
 21258	_PROTOTYPE( void wipe_inode, (struct inode *rip)                        );
 21259	
 21260	/* link.c */
 21261	_PROTOTYPE( int do_link, (void)                                         );
 21262	_PROTOTYPE( int do_unlink, (void)                                       );
 21263	_PROTOTYPE( int do_rename, (void)                                       );
 21264	_PROTOTYPE( void truncate, (struct inode *rip)                          );
 21265	
 21266	/* lock.c */
 21267	_PROTOTYPE( int lock_op, (struct filp *f, int req)                      );
 21268	_PROTOTYPE( void lock_revive, (void)                                    );
 21269	
 21270	/* main.c */
 21271	_PROTOTYPE( int main, (void)                                            );
 21272	_PROTOTYPE( void reply, (int whom, int result)                          );
 21273	
 21274	/* misc.c */
 21275	_PROTOTYPE( int do_dup, (void)                                          );
 21276	_PROTOTYPE( int do_exit, (void)                                         );
 21277	_PROTOTYPE( int do_fcntl, (void)                                        );
 21278	_PROTOTYPE( int do_fork, (void)                                         );
 21279	_PROTOTYPE( int do_exec, (void)                                         );
 21280	_PROTOTYPE( int do_revive, (void)                                       );
 21281	_PROTOTYPE( int do_set, (void)                                          );
 21282	_PROTOTYPE( int do_sync, (void)                                         );
 21283	_PROTOTYPE( int do_fsync, (void)                                        );
 21284	_PROTOTYPE( int do_reboot, (void)                                       );
 21285	_PROTOTYPE( int do_svrctl, (void)                                       );
 21286	_PROTOTYPE( int do_getsysinfo, (void)                                   );
 21287	
 21288	/* mount.c */
 21289	_PROTOTYPE( int do_mount, (void)                                        );
 21290	_PROTOTYPE( int do_umount, (void)                                       );
 21291	_PROTOTYPE( int unmount, (Dev_t dev)                                    );
 21292	
 21293	/* open.c */
 21294	_PROTOTYPE( int do_close, (void)                                        );
 21295	_PROTOTYPE( int do_creat, (void)                                        );
 21296	_PROTOTYPE( int do_lseek, (void)                                        );
 21297	_PROTOTYPE( int do_mknod, (void)                                        );
 21298	_PROTOTYPE( int do_mkdir, (void)                                        );
 21299	_PROTOTYPE( int do_open, (void)                                         );
 21300	
 21301	/* path.c */
 21302	_PROTOTYPE( struct inode *advance,(struct inode *dirp, char string[NAME_MAX]));
 21303	_PROTOTYPE( int search_dir, (struct inode *ldir_ptr,
 21304	                        char string [NAME_MAX], ino_t *numb, int flag)  );
 21305	_PROTOTYPE( struct inode *eat_path, (char *path)                        );
 21306	_PROTOTYPE( struct inode *last_dir, (char *path, char string [NAME_MAX]));
 21307	
 21308	/* pipe.c */
 21309	_PROTOTYPE( int do_pipe, (void)                                         );
 21310	_PROTOTYPE( int do_unpause, (void)                                      );
 21311	_PROTOTYPE( int pipe_check, (struct inode *rip, int rw_flag,
 21312	                        int oflags, int bytes, off_t position, int *canwrite, int notouch));
 21313	_PROTOTYPE( void release, (struct inode *ip, int call_nr, int count)    );
 21314	_PROTOTYPE( void revive, (int proc_nr, int bytes)                       );
 21315	_PROTOTYPE( void suspend, (int task)                                    );
 21316	_PROTOTYPE( int select_request_pipe, (struct filp *f, int *ops, int bl) );
 21317	_PROTOTYPE( int select_cancel_pipe, (struct filp *f)                    );
 21318	_PROTOTYPE( int select_match_pipe, (struct filp *f)                     );
 21319	
 21320	/* protect.c */
 21321	_PROTOTYPE( int do_access, (void)                                       );
 21322	_PROTOTYPE( int do_chmod, (void)                                        );
 21323	_PROTOTYPE( int do_chown, (void)                                        );
 21324	_PROTOTYPE( int do_umask, (void)                                        );
 21325	_PROTOTYPE( int forbidden, (struct inode *rip, mode_t access_desired)   );
 21326	_PROTOTYPE( int read_only, (struct inode *ip)                           );
 21327	
 21328	/* read.c */
 21329	_PROTOTYPE( int do_read, (void)                                         );
 21330	_PROTOTYPE( struct buf *rahead, (struct inode *rip, block_t baseblock,
 21331	                        off_t position, unsigned bytes_ahead)           );
 21332	_PROTOTYPE( void read_ahead, (void)                                     );
 21333	_PROTOTYPE( block_t read_map, (struct inode *rip, off_t position)       );
 21334	_PROTOTYPE( int read_write, (int rw_flag)                               );
 21335	_PROTOTYPE( zone_t rd_indir, (struct buf *bp, int index)                );
 21336	
 21337	/* stadir.c */
 21338	_PROTOTYPE( int do_chdir, (void)                                        );
 21339	_PROTOTYPE( int do_fchdir, (void)                                       );
 21340	_PROTOTYPE( int do_chroot, (void)                                       );
 21341	_PROTOTYPE( int do_fstat, (void)                                        );
 21342	_PROTOTYPE( int do_stat, (void)                                         );
 21343	_PROTOTYPE( int do_fstatfs, (void)                                      );
 21344	
 21345	/* super.c */
 21346	_PROTOTYPE( bit_t alloc_bit, (struct super_block *sp, int map, bit_t origin));
 21347	_PROTOTYPE( void free_bit, (struct super_block *sp, int map,
 21348	                                                bit_t bit_returned)     );
 21349	_PROTOTYPE( struct super_block *get_super, (Dev_t dev)                  );
 21350	_PROTOTYPE( int mounted, (struct inode *rip)                            );
 21351	_PROTOTYPE( int read_super, (struct super_block *sp)                    );
 21352	_PROTOTYPE( int get_block_size, (dev_t dev)                             );
 21353	
 21354	/* time.c */
 21355	_PROTOTYPE( int do_stime, (void)                                        );
 21356	_PROTOTYPE( int do_utime, (void)                                        );
 21357	
 21358	/* utility.c */
 21359	_PROTOTYPE( time_t clock_time, (void)                                   );
 21360	_PROTOTYPE( unsigned conv2, (int norm, int w)                           );
 21361	_PROTOTYPE( long conv4, (int norm, long x)                              );
 21362	_PROTOTYPE( int fetch_name, (char *path, int len, int flag)             );
 21363	_PROTOTYPE( int no_sys, (void)                                          );
 21364	_PROTOTYPE( void panic, (char *who, char *mess, int num)                );
 21365	
 21366	/* write.c */
 21367	_PROTOTYPE( void clear_zone, (struct inode *rip, off_t pos, int flag)   );
 21368	_PROTOTYPE( int do_write, (void)                                        );
 21369	_PROTOTYPE( struct buf *new_block, (struct inode *rip, off_t position)  );
 21370	_PROTOTYPE( void zero_block, (struct buf *bp)                           );
 21371	
 21372	/* select.c */
 21373	_PROTOTYPE( int do_select, (void)                                       );
 21374	_PROTOTYPE( int select_callback, (struct filp *, int ops)               );
 21375	_PROTOTYPE( void select_forget, (int fproc)                             );
 21376	_PROTOTYPE( void select_timeout_check, (timer_t *)                      );
 21377	_PROTOTYPE( void init_select, (void)                                    );
 21378	_PROTOTYPE( int select_notified, (int major, int minor, int ops)        );
 21379	
 21380	/* timers.c */
 21381	_PROTOTYPE( void fs_set_timer, (timer_t *tp, int delta, tmr_func_t watchdog, int arg));
 21382	_PROTOTYPE( void fs_expire_timers, (clock_t now)                        );
 21383	_PROTOTYPE( void fs_cancel_timer, (timer_t *tp)                         );
 21384	_PROTOTYPE( void fs_init_timer, (timer_t *tp)                           );
 21385	
 21386	/* cdprobe.c */
 21387	_PROTOTYPE( int cdprobe, (void)                                         );

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/glo.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 21400	/* EXTERN определяется как внешнее везде, исключая файл table.c */
 21401	#ifdef _TABLE
 21402	#undef EXTERN
 21403	#define EXTERN
 21404	#endif
 21405	
 21406	/* Глобальные переменные системы */
 21407	EXTERN struct fproc *fp;        /* указатель на структуру вызывающего процесса */
 21408	EXTERN int super_user;          /* 1, если вызов от суперпользователя, иначе 0 */
 21409	EXTERN int susp_count;          /* число процессов, приостановленных на чтении из канала */
 21410	EXTERN int nr_locks;            /* текущее число захватов */
 21411	EXTERN int reviving;            /* число возобновляемых процессов */
 21412	EXTERN off_t rdahedpos;         /* положение для опережающего чтения */
 21413	EXTERN struct inode *rdahed_inode;      /* указатель на индексный узел для опережающего чтения */
 21414	EXTERN Dev_t root_dev;          /* номер корневого устройства */
 21415	EXTERN time_t boottime;         /* время в секундах на момент загрузки системы */
 21416	
 21417	/* Параметры вызова. */
 21418	EXTERN message m_in;            /* входное сообщение */
 21419	EXTERN message m_out;           /* выходное сообщение-ответ */
 21420	EXTERN int who;                 /* номер вызывающего процесса */
 21421	EXTERN int call_nr;             /* номер системного вызова */
 21422	EXTERN char user_path[PATH_MAX];/* хранит путь пользователя */
 21423	
 21424	/* Переменные, используемые для возврата результата вызывающему процессу. */
 21425	EXTERN int err_code;            /* временно хранит номер ошибки */
 21426	EXTERN int rdwt_err;            /* состоятие последнего запроса на дисковый ввод-вывод */
 21427	
 21428	/* Данные, инициализируемые в других местах. */
 21429	extern _PROTOTYPE (int (*call_vec[]), (void) ); /* таблица системных вызовов */
 21430	extern char dot1[2];   /* dot1 (&dot1[0]) и dot2 (&dot2[0]) имеют особое значение */
 21431	extern char dot2[3];   /* для search_dir:  проверка разрешений доступа не выполняется. */




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/fproc.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 21500	/* Информация, относящаяся к процессу. Для каждого потенциального процесса резервируется
 21501	 * запись, поэтому значение NR_PROCS должно быть такое же, как и в ядре. Здесь невозможно
 21502	 * и не нужно определять, свободна ли запись.
 21503	 */
 21504	EXTERN struct fproc {
 21505	  mode_t fp_umask;              /* маска, устанавливаемая системным вызовом umask */
 21506	  struct inode *fp_workdir;     /* указатель на индексный узел рабочего каталога */
 21507	  struct inode *fp_rootdir;     /* указатель на текущий корневой каталог (см. chroot) */
 21508	  struct filp *fp_filp[OPEN_MAX]; /* таблица дескрипторов файлов */
 21509	  uid_t fp_realuid;             /* реальное значение id пользователя */
 21510	  uid_t fp_effuid;              /* эффективное значение id пользователя */
 21511	  gid_t fp_realgid;             /* реальное значение id группы */
 21512	  gid_t fp_effgid;              /* эффективное значение id группы */
 21513	  dev_t fp_tty;                 /* главный/вспомогательный номер управляющего терминала */
 21514	  int fp_fd;                    /* здесь сохраняется дескриптор файла, если не удается завершить чт/зп */
 21515	  char *fp_buffer;              /* здесь сохраняется буфер, если не удается завершить чт/зп */
 21516	  int  fp_nbytes;               /* здесь сохраняются байты, если не удается завершить чт/зп */
 21517	  int  fp_cum_io_partial;       /* неполный счетчик байтов, если не удается завершить чт/зп */
 21518	  char fp_suspended;            /* устанавливается при приостановке процесса */
 21519	  char fp_revived;              /* устанавливается при возобновлении процесса */
 21520	  char fp_task;                 /* задание, на котором приостановлен процесс */
 21521	  char fp_sesldr;               /* true, если процесс является лидером сеанса */
 21522	  pid_t fp_pid;                 /* id процесса */
 21523	  long fp_cloexec;              /* битовая карта для FD_CLOEXEC (POSIX Table 6-2)*/
 21524	} fproc[NR_PROCS];
 21525	
 21526	/* Значения полей. */
 21527	#define NOT_SUSPENDED      0    /* процесс не приостановлен каналом или заданием */
 21528	#define SUSPENDED          1    /* процесс приостановлен каналом или заданием */
 21529	#define NOT_REVIVING       0    /* процесс не возобновляется */
 21530	#define REVIVING           1    /* процесс возобновляется  */
 21531	#define PID_FREE           0    /* запись процесса свободна */
 21532	
 21533	/* Проверка допустимости номера процесса – включает системные процессы. */
 21534	#define isokprocnr(n)   ((unsigned)((n)+NR_TASKS) < NR_PROCS + NR_TASKS)
 21535	





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/buf.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 21600	/* Кэш блоков.  Чтобы получить блок, вызывается функция get_block() с указанием
 21601	 * желаемого блока. Затем блок помечается как используемый, и значение его поля
 21602	 * 'b_count' инкрементируется. Все неиспользуемые блоки объединяются в LRU-список,
 21603	 * где 'front' указывает блок с самым давним сроком использования, а 'rear' – на
 21604	 * последний использованный блок. Поддерживается и обратная цепочка, задействующая
 21605	 * поле b_prev.
 21606	 * При использовании LRU учитывается время вызова функции put_block(). Второй параметр
 21607	 * put_block() может нарушить порядок LRU и поместить блок в начало списка, если велика
 21608	 * вероятность его применения в ближайшем будущем. Если блок изменяется, процедура,
 21609	 * изменяющая его, должна установить переменную b_dirt в значение DIRTY, чтобы блок в
 21610	 * конечном счете был записан на диск.
 21611	 */
 21612	
 21613	#include <sys/dir.h>
 21614	#include <dirent.h>
 21615	
 21616	EXTERN struct buf {
 21617	  /* Часть буфера, содержащая данные. */
 21618	  union {
 21619	    char b__data[MAX_BLOCK_SIZE];                    /* обычные данные поьзователя */
 21620	/* блок каталога */
 21621	    struct direct b__dir[NR_DIR_ENTRIES(MAX_BLOCK_SIZE)];    
 21622	/* косвенный блок V1 */
 21623	    zone1_t b__v1_ind[V1_INDIRECTS];         
 21624	/* косвенный блок V2 */
 21625	    zone_t  b__v2_ind[V2_INDIRECTS(MAX_BLOCK_SIZE)];         
 21626	/* блок индексного узла V1 */
 21627	    d1_inode b__v1_ino[V1_INODES_PER_BLOCK]; 
 21628	/* блок индексного узла V2 */
 21629	    d2_inode b__v2_ino[V2_INODES_PER_BLOCK(MAX_BLOCK_SIZE)]; 
 21630	/* блок битовой карты */
 21631	    bitchunk_t b__bitmap[FS_BITMAP_CHUNKS(MAX_BLOCK_SIZE)];  
 21632	  } b;
 21633	
 21634	  /* Заголовочная часть буфера. */
 21635	  struct buf *b_next;           /* используется для связывания всех свободных буферов в цепочку */
 21636	  struct buf *b_prev;           /* используется для обратного связывания всех свободных буферов */
 21637	  struct buf *b_hash;           /* используется для связывания буферов в хеш-цепочку */
 21638	  block_t b_blocknr;            /* номер блока (вспомогательного) устройства */
 21639	  dev_t b_dev;                  /* главное | вспомогательное устройство, на котором расположен блок */
 21640	  char b_dirt;                  /* CLEAN или DIRTY */
 21641	  char b_count;                 /* число пользователей этого буфера */
 21642	} buf[NR_BUFS];
 21643	
 21644	/* Блок свободен, если b_dev == NO_DEV. */
 21645	
 21646	#define NIL_BUF ((struct buf *) 0)      /* указывает на отсутствие буфера */
 21647	
 21648	/* Эти определения позволяют использовать bp->b_data вместо bp->b.b__data */
 21649	#define b_data   b.b__data
 21650	#define b_dir    b.b__dir
 21651	#define b_v1_ind b.b__v1_ind
 21652	#define b_v2_ind b.b__v2_ind
 21653	#define b_v1_ino b.b__v1_ino
 21654	#define b_v2_ino b.b__v2_ino
 21655	#define b_bitmap b.b__bitmap
 21656	
 21657	EXTERN struct buf *buf_hash[NR_BUF_HASH];       /* хеш-таблица буферов */
 21658	
 21659	EXTERN struct buf *front;   /* указывает на свободный блок с самым давним сроком использования */
 21660	EXTERN struct buf *rear;    /* указывает на свободный блок с самым недавним сроком использования */
 21661	EXTERN int bufs_in_use;     /* число буферов, используемых в текущий момент */
 21662	
 21663	/* При освобождении блока тип использования передается put_block(). */
 21664	#define WRITE_IMMED   0100 /* теперь блок должен быть записан на диск */
 21665	#define ONE_SHOT      0200 /* устанавливается, если вероятность скорого вызова блока мала */
 21666	
 21667	#define INODE_BLOCK        0                             /* блок индексного узла */
 21668	#define DIRECTORY_BLOCK    1                             /* блок каталога */
 21669	#define INDIRECT_BLOCK     2                             /* блок указателя */
 21670	#define MAP_BLOCK          3                             /* битовая карта */
 21671	#define FULL_DATA_BLOCK    5                             /* данные, использованные полностью */
 21672	#define PARTIAL_DATA_BLOCK 6                             /* данные, использованные частично */
 21673	
 21674	#define HASH_MASK (NR_BUF_HASH - 1)     /* маска для хеширования номеров блоков */

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/file.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 21700	/* Таблица filp – посредник между дескрипторами файлов и индексного узлами. Запись свободна,
 21701	 * если filp_count == 0.
 21702	 */
 21703	
 21704	EXTERN struct filp {
 21705	  mode_t filp_mode;             /* RW-биты, указывающие режим открытия файла */
 21706	  int filp_flags;               /* флаги open и fcntl */
 21707	  int filp_count;               /* число дескрипторов файла, использующих эту запись */
 21708	  struct inode *filp_ino;       /* указатель на индексный узел */
 21709	  off_t filp_pos;               /* позиция файла */
 21710	
 21711	  /* следующие поля предназначены для select() и принадлежат общему коду select()
 21712	   * (то есть код select(), зависимый от типа дескриптора, не использует их).
 21713	   */
 21714	  int filp_selectors;           /* выбор процессов, блокируемых этим дескриптором */
 21715	  int filp_select_ops;          /* операции для выбора */
 21716	
 21717	  /* Поля для кода select(), зависимого от типа дескриптора */
 21718	  int filp_pipe_select_ops;
 21719	} filp[NR_FILPS];
 21720	
 21721	#define FILP_CLOSED     0       /* filp_mode:  связанное устройство закрыто */
 21722	
 21723	#define NIL_FILP (struct filp *) 0      /* указывает на отсутствие записи в filp */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/lock.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 21800	/* Таблица блокированных файлов. Как и filp, она указывает на таблицу
 21801	 * индексных узлов, но для блокирования.
 21802	 */
 21803	EXTERN struct file_lock {
 21804	  short lock_type;              /* F_RDLOCK или F_WRLOCK; 0 означает неиспользуемую запись */
 21805	  pid_t lock_pid;               /* pid блокирующего процесса */
 21806	  struct inode *lock_inode;     /* указатель на блокированный индексный узел */
 21807	  off_t lock_first;             /* смещение первого блокированного байта */
 21808	  off_t lock_last;              /* смещение последнего блокированного байта  */
 21809	} file_lock[NR_LOCKS];

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/inode.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 21900	/* Таблица индексных узлов. Она содержит индексные узлы, используемые в текущий момент. В
 21901	 * одних случаях они открываются системным вызовом open() или creat(),
 21902	 * в других самой файловой системе нужен индексный узел, например, для поиска
 21903	 * пути в каталоге. 
 21904	 * Первая часть структуры содержит поля, присутствующие на диске, вторая –
 21905	 * поля, отсутствующие на диске. Первая часть также объявлена в файле
 21906	 * "type.h" как 'd1_inode' для файловых систем V1 и как 'd2_inode' для
 21907	 * файловых систем V2.
 21908	 */
 21909	
 21910	EXTERN struct inode {
 21911	  mode_t i_mode;                /* тип файла, защита и т. д. */
 21912	  nlink_t i_nlinks;             /* число связей файла */
 21913	  uid_t i_uid;                  /* идентификатор пользователя владельца файла */
 21914	  gid_t i_gid;                  /* номер группы */
 21915	  off_t i_size;                 /* текущий размер файла в байтах */
 21916	  time_t i_atime;               /* время последнего доступа (только в V2) */
 21917	  time_t i_mtime;               /* время последнего изменения данных */
 21918	  time_t i_ctime;               /* время последнего изменения индексного узла (только в V2)*/
 21919	  zone_t i_zone[V2_NR_TZONES];  /* номера зон для прямой, косвенной и дважды косвенной зоны */
 21920	  
 21921	  /* Следующие элементы не присутствуют на диске. */
 21922	  dev_t i_dev;                  /* устройство, на котором расположен индексный узел*/
 21923	  ino_t i_num;                  /* номер индексного узла на (вспомогательном) устройстве */
 21924	  int i_count;                  /* число использований индексного узла; 0 означает, что запись свободна */
 21925	  int i_ndzones;                /* число прямых зон (Vx_NR_DZONES) */
 21926	  int i_nindirs;                /* число косвенных зон на косвенный блок */
 21927	  struct super_block *i_sp;     /* указатель на суперблок устройства индексного узла */
 21928	  char i_dirt;                  /* CLEAN или DIRTY */
 21929	  char i_pipe;                  /* устанавливается в I_PIPE для канала */
 21930	  char i_mount;                 /* бит, устанавливаемый для монтируемого файла */
 21931	  char i_seek;                  /* устанавливается LSEEK, очищается READ/WRITE */
 21932	  char i_update;                /* содержит биты ATIME, CTIME и MTIME */
 21933	} inode[NR_INODES];
 21934	
 21935	#define NIL_INODE (struct inode *) 0    /* указывает на отсутствие записи индексного узла */
 21936	
 21937	/* Значения полей. Обратите внимание на то, что CLEAN и DIRTY определены в "const.h" */
 21938	#define NO_PIPE            0    /* i_pipe равна NO_PIPE, если индексный узел - не канал */
 21939	#define I_PIPE             1    /* i_pipe равна I_PIPE, если индексный узел - канал */
 21940	#define NO_MOUNT           0    /* i_mount равна NO_MOUNT, если файл не монтирован /
 21941	#define I_MOUNT            1    /* i_mount равна I_MOUNT, есле файл монтирован */
 21942	#define NO_SEEK            0    /* i_seek = NO_SEEK, если последняя операция – не SEEK */
 21943	#define ISEEK              1    /* i_seek = ISEEK, если последняя операция – SEEK*/


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/param.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 22000	/* Следующие имена являются синонимами переменных во входном сообщении. */
 22001	#define acc_time      m2_l1
 22002	#define addr          m1_i3
 22003	#define buffer        m1_p1
 22004	#define child         m1_i2
 22005	#define co_mode       m1_i1
 22006	#define eff_grp_id    m1_i3
 22007	#define eff_user_id   m1_i3
 22008	#define erki          m1_p1
 22009	#define fd            m1_i1
 22010	#define fd2           m1_i2
 22011	#define ioflags       m1_i3
 22012	#define group         m1_i3
 22013	#define real_grp_id   m1_i2
 22014	#define ls_fd         m2_i1
 22015	#define mk_mode       m1_i2
 22016	#define mk_z0         m1_i3
 22017	#define mode          m3_i2
 22018	#define c_mode        m1_i3
 22019	#define c_name        m1_p1
 22020	#define name          m3_p1
 22021	#define name1         m1_p1
 22022	#define name2         m1_p2
 22023	#define name_length   m3_i1
 22024	#define name1_length  m1_i1
 22025	#define name2_length  m1_i2
 22026	#define nbytes        m1_i2
 22027	#define owner         m1_i2
 22028	#define parent        m1_i1
 22029	#define pathname      m3_ca1
 22030	#define pid           m1_i3
 22031	#define pro           m1_i1
 22032	#define ctl_req       m4_l1
 22033	#define driver_nr     m4_l2
 22034	#define dev_nr        m4_l3
 22035	#define dev_style     m4_l4
 22036	#define rd_only       m1_i3
 22037	#define real_user_id  m1_i2
 22038	#define request       m1_i2
 22039	#define sig           m1_i2
 22040	#define slot1         m1_i1
 22041	#define tp            m2_l1
 22042	#define utime_actime  m2_l1
 22043	#define utime_modtime m2_l2
 22044	#define utime_file    m2_p1
 22045	#define utime_length  m2_i1
 22046	#define utime_strlen  m2_i2
 22047	#define whence        m2_i2
 22048	#define svrctl_req    m2_i1
 22049	#define svrctl_argp   m2_p1
 22050	#define pm_stime      m1_i1
 22051	#define info_what     m1_i1
 22052	#define info_where    m1_p1
 22053	
 22054	/* Следующие имена являются синотимами переменных в выходном сообщении. */
 22055	#define reply_type    m_type
 22056	#define reply_l1      m2_l1
 22057	#define reply_i1      m1_i1
 22058	#define reply_i2      m1_i2
 22059	#define reply_t1      m4_l1
 22060	#define reply_t2      m4_l2
 22061	#define reply_t3      m4_l3
 22062	#define reply_t4      m4_l4
 22063	#define reply_t5      m4_l5


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/super.h
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 22100	/* Таблица суперблоков. Корневая файловая система и все монтируемые файловые системы
 22101	 * имеют в ней записи, содержащие информацию о размерах битовых карт и индексных узлов.
 22102	 * Поле s_ninodes содержит число индексных узлов, доступных для файлов и каталогов, включая
 22103	 * корневой каталог. Индексный узел 0 находится на диске, но не используется. Таким образом, 
 22104	 * s_ninodes = 4 означает, что в битовой карте будут использованы 5 бит, бит 0 всегда
 22105	 * равен 1 и не используется, а биты 1-4 соответствуют файлам и каталогам.
 22106	 * Структура диска следующая: 
 22107	 *
 22108	 *    элемент                число блоков
 22109	 *    загрузочный блок       1
 22110	 *    суперблок              1    (смещение 1kB)
 22111	 *    карта индексных узлов  s_imap_blocks
 22112	 *    карта зон              s_zmap_blocks
 22113	 *    индексные узлы         (s_ninodes + 'индексных узлов на блок' - 1)/'индексных узлов на блок'
 22114	 *    не используется        все, что нужно для заполнения текущей зоны
 22115	 *    зоны данных            (s_zones - s_firstdatazone) << s_log_zone_size
 22116	 *
 22117	 * Запись super_block slot свободна, если s_dev == NO_DEV. 
 22118	 */
 22119	
 22120	EXTERN struct super_block {
 22121	  ino_t s_ninodes;              /* число доступных для использования индексных узлов на вспомогательном устройстве */
 22122	  zone1_t  s_nzones;            /* общий размер устройства включая битовые карты и т. д. */
 22123	  short s_imap_blocks;          /* число блоков, используемых битовой картой индексных узлов */
 22124	  short s_zmap_blocks;          /* число блоков, используемых битовой картой зон */
 22125	  zone1_t s_firstdatazone;      /* номер первой зоны данных */
 22126	  short s_log_zone_size;        /* log2 размера блоков на зону */
 22127	  short s_pad;                  /* попытка избежать заполнения, зависящего от компилятора */
 22128	  off_t s_max_size;             /* максимальный размер файла для этого устройства */
 22129	  zone_t s_zones;               /* число зон (заменяет s_nzones в V2) */
 22130	  short s_magic;                /* магическое число для распознания суперблока */
 22131	
 22132	  /* Следующие переменные имеют отношение к дискам с файловой системой V3 и выше */
 22133	
 22134	  /* Размер блока в байтах (минимальный - MIN_BLOCK SIZE), кратный SECTOR_SIZE.
 22135	   * В файловых системах V1 и V2 размер блока должен иметь начальное значение
 22136	   * STATIC_BLOCK_SIZE. Максимальное знечение - MAX_BLOCK_SIZE.
 22137	   */
 22138	  short s_pad2;                 /* попытка избежать заполнения, зависящего от компилятора */
 22139	  unsigned short s_block_size;  /* размер блока в байтах. */
 22140	  char s_disk_version;          /* вспомогательный номер версии файловой системы */
 22141	
 22142	  /* Следующие переменные используются только при наличии суперблока в памяти. */
 22143	  struct inode *s_isup;         /* индексный узел для корневого каталога монтированной файловой системы */
 22144	  struct inode *s_imount;       /* монтируемый индексный узел */
 22145	  unsigned s_inodes_per_block;  /* вычисляется из магического числа */
 22146	  dev_t s_dev;                  /* чей суперблок? */
 22147	  int s_rd_only;                /* устанавливается в 1, если файловая система монтирована только для чтения */
 22148	  int s_native;                 /* устанавливается в 1, если файловая система с прямым порядком следования байтов */
 22149	  int s_version;                /* версия файловой системы, 0 означает неправильное магическое число */
 22150	  int s_ndzones;                /* число прямых зон в индексном узле */
 22151	  int s_nindirs;                /* число косвенных зон на косвенный блок */
 22152	  bit_t s_isearch;              /* индексные узлы меньше этого числа используются */
 22153	  bit_t s_zsearch;              /* все зоны меньше этого числа используются */
 22154	} super_block[NR_SUPERS];
 22155	
 22156	#define NIL_SUPER (struct super_block *) 0
 22157	#define IMAP            0       /* работа с битовой картой индексного узла */
 22158	#define ZMAP            1       /* работа с битовой картой зоны */


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/table.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 22200	/* Этот файл содержит таблицу, используемую для связывания номеров системных вызовов с
 22201	 * выполняющими их функциями.
 22202	 */
 22203	
 22204	#define _TABLE
 22205	
 22206	#include "fs.h"
 22207	#include <minix/callnr.h>
 22208	#include <minix/com.h>
 22209	#include "buf.h"
 22210	#include "file.h"
 22211	#include "fproc.h"
 22212	#include "inode.h"
 22213	#include "lock.h"
 22214	#include "super.h"
 22215	
 22216	PUBLIC _PROTOTYPE (int (*call_vec[]), (void) ) = {
 22217	        no_sys,         /*  0 = не используется  */
 22218	        do_exit,        /*  1 = exit    */
 22219	        do_fork,        /*  2 = fork    */
 22220	        do_read,        /*  3 = read    */
 22221	        do_write,       /*  4 = write   */
 22222	        do_open,        /*  5 = open    */
 22223	        do_close,       /*  6 = close   */
 22224	        no_sys,         /*  7 = wait    */
 22225	        do_creat,       /*  8 = creat   */
 22226	        do_link,        /*  9 = link    */
 22227	        do_unlink,      /* 10 = unlink  */
 22228	        no_sys,         /* 11 = waitpid */
 22229	        do_chdir,       /* 12 = chdir   */
 22230	        no_sys,         /* 13 = time    */
 22231	        do_mknod,       /* 14 = mknod   */
 22232	        do_chmod,       /* 15 = chmod   */
 22233	        do_chown,       /* 16 = chown   */
 22234	        no_sys,         /* 17 = break   */
 22235	        do_stat,        /* 18 = stat    */
 22236	        do_lseek,       /* 19 = lseek   */
 22237	        no_sys,         /* 20 = getpid  */
 22238	        do_mount,       /* 21 = mount   */
 22239	        do_umount,      /* 22 = umount  */
 22240	        do_set,         /* 23 = setuid  */
 22241	        no_sys,         /* 24 = getuid  */
 22242	        do_stime,       /* 25 = stime   */
 22243	        no_sys,         /* 26 = ptrace  */
 22244	        no_sys,         /* 27 = alarm   */
 22245	        do_fstat,       /* 28 = fstat   */
 22246	        no_sys,         /* 29 = pause   */
 22247	        do_utime,       /* 30 = utime   */
 22248	        no_sys,         /* 31 = (stty)  */
 22249	        no_sys,         /* 32 = (gtty)  */
 22250	        do_access,      /* 33 = access  */
 22251	        no_sys,         /* 34 = (nice)  */
 22252	        no_sys,         /* 35 = (ftime) */
 22253	        do_sync,        /* 36 = sync    */
 22254	        no_sys,         /* 37 = kill    */
 22255	        do_rename,      /* 38 = rename  */
 22256	        do_mkdir,       /* 39 = mkdir   */
 22257	        do_unlink,      /* 40 = rmdir   */
 22258	        do_dup,         /* 41 = dup     */
 22259	        do_pipe,        /* 42 = pipe    */
 22260	        no_sys,         /* 43 = times   */
 22261	        no_sys,         /* 44 = (prof)  */
 22262	        no_sys,         /* 45 = unused  */
 22263	        do_set,         /* 46 = setgid  */
 22264	        no_sys,         /* 47 = getgid  */
 22265	        no_sys,         /* 48 = (signal)*/
 22266	        no_sys,         /* 49 = unused  */
 22267	        no_sys,         /* 50 = unused  */
 22268	        no_sys,         /* 51 = (acct)  */
 22269	        no_sys,         /* 52 = (phys)  */
 22270	        no_sys,         /* 53 = (lock)  */
 22271	        do_ioctl,       /* 54 = ioctl   */
 22272	        do_fcntl,       /* 55 = fcntl   */
 22273	        no_sys,         /* 56 = (mpx)   */
 22274	        no_sys,         /* 57 = unused  */
 22275	        no_sys,         /* 58 = unused  */
 22276	        do_exec,        /* 59 = execve  */
 22277	        do_umask,       /* 60 = umask   */
 22278	        do_chroot,      /* 61 = chroot  */
 22279	        do_setsid,      /* 62 = setsid  */
 22280	        no_sys,         /* 63 = getpgrp */
 22281	
 22282	        no_sys,         /* 64 = KSIG:  сигналы из ядра */
 22283	        do_unpause,     /* 65 = UNPAUSE */
 22284	        no_sys,         /* 66 = unused  */
 22285	        do_revive,      /* 67 = REVIVE  */
 22286	        no_sys,         /* 68 = TASK_REPLY      */
 22287	        no_sys,         /* 69 = не используется */
 22288	        no_sys,         /* 70 = не используется */
 22289	        no_sys,         /* 71 = si */
 22290	        no_sys,         /* 72 = sigsuspend */
 22291	        no_sys,         /* 73 = sigpending */
 22292	        no_sys,         /* 74 = sigprocmask */
 22293	        no_sys,         /* 75 = sigreturn */
 22294	        do_reboot,      /* 76 = reboot */
 22295	        do_svrctl,      /* 77 = svrctl */
 22296	
 22297	        no_sys,         /* 78 = не используется */
 22298	        do_getsysinfo,  /* 79 = getsysinfo */
 22299	        no_sys,         /* 80 = не используется */
 22300	        do_devctl,      /* 81 = devctl */
 22301	        do_fstatfs,     /* 82 = fstatfs */
 22302	        no_sys,         /* 83 = memalloc */
 22303	        no_sys,         /* 84 = memfree */
 22304	        do_select,      /* 85 = select */
 22305	        do_fchdir,      /* 86 = fchdir */
 22306	        do_fsync,       /* 87 = fsync */
 22307	        no_sys,         /* 88 = getpriority */
 22308	        no_sys,         /* 89 = setpriority */
 22309	        no_sys,         /* 90 = gettimeofday */
 22310	};
 22311	/* Здесь не должно быть ошибки, связанной с отрицательным размером массива  */
 22312	extern int dummy[sizeof(call_vec) == NCALLS * sizeof(call_vec[0]) ? 1 :  -1];
 22313	


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/cache.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 22400	/* Файловая система поддерживает буферный кэш для сокращения
 22401	 * числа обращений к диску. Каждый раз при выполнении
 22402	 * операции чтения или записи сначала проверяется наличие
 22403	 * блока в кэше. Этот файл осуществляет управление кэшем
 22404	 * блоков.
 22405	 * Этот файл имеет следующие точки входа: 
 22406	 *   get_block:    запрос доставки из кэша блока для чтения или записи
 22407	 *   put_block:    возврат блока, ранее запрошенного вызовом get_block
 22408	 *   alloc_zone:   выделение новой зоны (для увеличения длины файла)
 22409	 *   free_zone:    освобождение зоны (при удалении файла)
 22410	 *   rw_block:     чтение блока с диска или запись блока
 22411	 *   invalidate:   удаление всех блоков из кэша устройства
 22412	 */
 22413	
 22414	#include "fs.h"
 22415	#include <minix/com.h>
 22416	#include "buf.h"
 22417	#include "file.h"
 22418	#include "fproc.h"
 22419	#include "super.h"
 22420	
 22421	FORWARD _PROTOTYPE( void rm_lru, (struct buf *bp) );
 22422	
 22423	/*===========================================================================*
 22424	 *                              get_block                                    *
 22425	 *===========================================================================*/
 22426	PUBLIC struct buf *get_block(dev, block, only_search)
 22427	register dev_t dev;             /* устройство, на котором расположен блок */
 22428	register block_t block;         /* нужный блок */
 22429	int only_search;                /* при NO_READ не выполнять чтение */
 22430	{
 22431	/* Проверка наличия запрошенного блока в кэше. При наличии блока возвращается
 22432	 * указатель на него, иначе блок помещается в кэш на место какого-либо другого
 22433	 * блока (если значение 'only_search' не равно 1). Все неиспользуемые блоки кэша объединяются
 22434	 * в цепочку, где 'front' указывает на блок с самым давним сроком использования, а 'rear' -
 22435	 * на блок, использовшийся последним.  Если значение 'only_search' равно 1, запрашиваемый
 22436	 * блок будет полностью перезаписан, поэтому необходимо лишь убедиться в его наличии в
 22437	 * кэше; в его отсутствие подойдет любой свободный буфер. Не обязательно фактически
 22438	 * считывать блок с диска.
 22439	 * Если 'only_search' = PREFETCH, блок не нужно считывать с диска, и для блока не нужно
 22440	 * отмечать устройство, чтобы запрашивающие процессы могли определить его действительность.
 22441	 * Кроме LRU-цепочки имеется также хеш-цепочка, связывающая блоки, номера которых 
 22442	 * оканчиваются одинаковыми последовательностями битов. Это ускоряет поиск.
 22443	 *
 22444	 */
 22445	
 22446	  int b;
 22447	  register struct buf *bp, *prev_ptr;
 22448	
 22449	  /* Поиск в хеш-цепочке пары (устройство, блок). Вызов do_read() может использовать
 22450	   * get_block(NO_DEV ...) для получения неименованного блока с целью заполнения
 22451	   * нулями, если какой-либо процесс захочет считать "дырку" в файле. В этом случае поиск
 22452	   * не выполняется
 22453	   */
 22454	  if (dev != NO_DEV) {
 22455	        b = (int) block & HASH_MASK;
 22456	        bp = buf_hash[b];
 22457	        while (bp != NIL_BUF) {
 22458	                if (bp->b_blocknr == block && bp->b_dev == dev) {
 22459	                        /* Block needed has been found. */
 22460	                        if (bp->b_count == 0) rm_lru(bp);
 22461	                        bp->b_count++;  /* пометка блока как используемого */
 22462	
 22463	                        return(bp);
 22464	                } else {
 22465	                        /* Этот блок не искомый. */
 22466	                        bp = bp->b_hash; /* переход к следующему блоку хеш-цепочки */
 22467	                }
 22468	        }
 22469	  }
 22470	
 22471	  /* Желаемый блок не находится в доступной цепочке. Выбор самого старого блока ('front'). */
 22472	  if ((bp = front) == NIL_BUF) panic(__FILE__,"all buffers in use", NR_BUFS);
 22473	  rm_lru(bp);
 22474	
 22475	  /* Удаление блока, только что выбранного из хеш-цепочки. */
 22476	  b = (int) bp->b_blocknr & HASH_MASK;
 22477	  prev_ptr = buf_hash[b];
 22478	  if (prev_ptr == bp) {
 22479	        buf_hash[b] = bp->b_hash;
 22480	  } else {
 22481	        /* Выбранный блок не находится в начале своей хеш-цепочки. */
 22482	        while (prev_ptr->b_hash != NIL_BUF)
 22483	                if (prev_ptr->b_hash == bp) {
 22484	                        prev_ptr->b_hash = bp->b_hash;  /* найден */
 22485	                        break;
 22486	                } else {
 22487	                        prev_ptr = prev_ptr->b_hash;    /* продолжение поиска */
 22488	                }
 22489	  }
 22490	
 22491	  /* Если выбранный блок был изменен, сбросить его на диск.
 22492	   * Сброс всех остальных измененных блоков этого же устройства во избежание задержки
 22493	   */
 22494	  if (bp->b_dev != NO_DEV) {
 22495	        if (bp->b_dirt == DIRTY) flushall(bp->b_dev);
 22496	  }
 22497	
 22498	  /* Заполнение параметров блока и его добавление в хеш-цепочку. */
 22499	  bp->b_dev = dev;              /* номер устройства */
 22500	  bp->b_blocknr = block;        /* номер блока */
 22501	  bp->b_count++;                /* пометка блока как используемого */
 22502	  b = (int) bp->b_blocknr & HASH_MASK;
 22503	  bp->b_hash = buf_hash[b];
 22504	  buf_hash[b] = bp;             /* добавление в хеш-список */
 22505	
 22506	  /* Получение запрошенного блока, если не поиск и не предварительная выборка. */
 22507	  if (dev != NO_DEV) {
 22508	        if (only_search == PREFETCH) bp->b_dev = NO_DEV;
 22509	        else
 22510	        if (only_search == NORMAL) {
 22511	                rw_block(bp, READING);
 22512	        }
 22513	  }
 22514	  return(bp);                   /* возврат полученного блока */
 22515	}
	
 22517	/*===========================================================================*
 22518	 *                              put_block                                    *
 22519	 *===========================================================================*/
 22520	PUBLIC void put_block(bp, block_type)
 22521	register struct buf *bp;        /* указатель на буфер, который требуется освободить */
 22522	int block_type;                 /* INODE_BLOCK, DIRECTORY_BLOCK или другой тип */
 22523	{
 22524	/* Возврат блока в список свободных блоков. В зависимости от типа, блок может быть помещен
 22525	 * в начало или в конец LRU-цепочки. Блоки, вероятность использования которых в ближайшее
 22526	 * время вешика (например, блоки данных, заполненные частично), помещаются в конец,
 22527	 * а блоки, скорое использование которых маловероятно (например, полные блоки данных),
 22528	 * помещаются в начало. Блоки, удаление которых может нарушить целостность файловой
 22529	 * системы (например, блоки индексных узлов), записываются на диск сразу же после
 22530	 * модификации.
 22531	 */
 22532	  if (bp == NIL_BUF) return;    /* проще проверить здесь, чем в вызывающем процессе */
 22533	
 22534	  bp->b_count--;                /* одним пользователем меньше */
 22535	  if (bp->b_count != 0) return; /* блок все еще используется */
 22536	
 22537	  bufs_in_use--;                /* одним используемым буфером меньше */
 22538	
 22539	  /* Возврат блока в LRU-цепочку. Если бит ONE_SHOT установлен в переменной 
 22540	   * 'block_type', скорое использование блока маловероятно, поэтому он помещается в начало
 22541	   * цепочки. Там он окажется первым блоком, который будет задействован при запросе свободного 
 22542	   * буфера.
 22543	   */
 22544	  if (bp->b_dev == DEV_RAM || block_type & ONE_SHOT) {
 22545	        /* Скорое использование блока маловероятно. Поместить его в начало цепочки.
 22546	         * Он будет удален из кэша первым.
 22547	         */
 22548	        bp->b_prev = NIL_BUF;
 22549	        bp->b_next = front;
 22550	        if (front == NIL_BUF)
 22551	                rear = bp;      /* LRU-цепочка была пуста */
 22552	        else
 22553	                front->b_prev = bp;
 22554	        front = bp;
 22555	  } else {
 22556	        /* Блок с большой вероятностью будет скоро использован. Поместить его в конец.
 22557	         * Он останется в кэше надолго.
 22558	         */
 22559	        bp->b_prev = rear;
 22560	        bp->b_next = NIL_BUF;
 22561	        if (rear == NIL_BUF)
 22562	                front = bp;
 22563	        else
 22564	                rear->b_next = bp;
 22565	        rear = bp;
 22566	  }
 22567	
 22568	  /* Некоторые блоки настолько важны (например, индексные узлы и косвенные блоки), что их нужно
 22569	   * сбрасывать на диск немедленно, чтобы избежать повреждения файловой системы в случае
 22570	   * аварии.
 22571	   */
 22572	  if ((block_type & WRITE_IMMED) && bp->b_dirt==DIRTY && bp->b_dev != NO_DEV) {
 22573	                rw_block(bp, WRITING);
 22574	  } 
 22575	}
	
 22577	/*===========================================================================*
 22578	 *                              alloc_zone                                   *
 22579	 *===========================================================================*/
 22580	PUBLIC zone_t alloc_zone(dev, z)
 22581	dev_t dev;                      /* устройство, на котором выделяется зона */
 22582	zone_t z;                       /* попытаться выделить новую зону по соседству с этой */
 22583	{
 22584	/* Выделение новой зоны на указанном устройстве и возврат ее номера. */
 22585	
 22586	  int major, minor;
 22587	  bit_t b, bit;
 22588	  struct super_block *sp;
 22589	
 22590	  /* Обратите внимание на то, что процедура alloc_bit() возвращает 1 для самой нижней
 22591	   * зоны, соответствующей sp->s_firstdatazone. Преобразование значения 'b', используемого
 22592	   * функцией alloc_bit(), в номер зоны 'z', хранимый в индексном узле, применяется следующая
 22593	   * формула: 
 22594	   *     z = b + sp->s_firstdatazone - 1
 22595	   * Alloc_bit() никогда не возвращает 0, поскольку он нужен для указания ошибки (NO_BIT).
 22596	   */
 22597	  sp = get_super(dev);
 22598	
 22599	  /* Если z = 0, пропустить полностью используемую начальную часть карты. */
 22600	  if (z == sp->s_firstdatazone) {
 22601	        bit = sp->s_zsearch;
 22602	  } else {
 22603	        bit = (bit_t) z - (sp->s_firstdatazone - 1);
 22604	  }
 22605	  b = alloc_bit(sp, ZMAP, bit);
 22606	  if (b == NO_BIT) {
 22607	        err_code = ENOSPC;
 22608	        major = (int) (sp->s_dev >> MAJOR) & BYTE;
 22609	        minor = (int) (sp->s_dev >> MINOR) & BYTE;
 22610	        printf("No space on %sdevice %d/%d\n",
 22611	                sp->s_dev == root_dev ? "root " :  "", major, minor);
 22612	        return(NO_ZONE);
 22613	  }
 22614	  if (z == sp->s_firstdatazone) sp->s_zsearch = b;      /* для следующего раза */
 22615	  return(sp->s_firstdatazone - 1 + (zone_t) b);
 22616	}
	
 22618	/*===========================================================================*
 22619	 *                              free_zone                                    *
 22620	 *===========================================================================*/
 22621	PUBLIC void free_zone(dev, numb)
 22622	dev_t dev;                              /* устройство, на котором выделяется зона */
 22623	zone_t numb;                            /* возвращаемая зона */
 22624	{
 22625	/* Возврат зоны. */
 22626	
 22627	  register struct super_block *sp;
 22628	  bit_t bit;
 22629	
 22630	  /* Поиск подходящего суперблока и возврат бита. */
 22631	  sp = get_super(dev);
 22632	  if (numb < sp->s_firstdatazone || numb >= sp->s_zones) return;
 22633	  bit = (bit_t) (numb - (sp->s_firstdatazone - 1));
 22634	  free_bit(sp, ZMAP, bit);
 22635	  if (bit < sp->s_zsearch) sp->s_zsearch = bit;
 22636	}
	
 22638	/*===========================================================================*
 22639	 *                              rw_block                                     *
 22640	 *===========================================================================*/
 22641	PUBLIC void rw_block(bp, rw_flag)
 22642	register struct buf *bp;        /* указатель на буфер */
 22643	int rw_flag;                    /* READING или WRITING */
 22644	{
 22645	/* Чтение или запись дискового блока. Это единственная функция, в которой выполняется фактический
 22646	 * ввод-вывод. В случае ошибки здесь печатается сообщение, однако запрашивающий процесс
 22647	 * не информируется об ошибке. Если ошибка произошла при очистке блока, неясно, что запрашивающий
 22648	 * процесс может сделать в такой ситуации.
 22649	 */
 22650	
 22651	  int r, op;
 22652	  off_t pos;
 22653	  dev_t dev;
 22654	  int block_size;
 22655	
 22656	  block_size = get_block_size(bp->b_dev);
 22657	
 22658	  if ( (dev = bp->b_dev) != NO_DEV) {
 22659	        pos = (off_t) bp->b_blocknr * block_size;
 22660	        op = (rw_flag == READING ? DEV_READ :  DEV_WRITE);
 22661	        r = dev_io(op, dev, FS_PROC_NR, bp->b_data, pos, block_size, 0);
 22662	        if (r != block_size) {
 22663	            if (r >= 0) r = END_OF_FILE;
 22664	            if (r != END_OF_FILE)
 22665	              printf("Unrecoverable disk error on device %d/%d, block %ld\n",
 22666	                        (dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE, bp->b_blocknr);
 22667	                bp->b_dev = NO_DEV;     /* теперь блок недействителен */
 22668	
 22669	                /* Информирование заинтересованных сторон об ошибках чтения. */
 22670	                if (rw_flag == READING) rdwt_err = r;
 22671	        }
 22672	  }
 22673	
 22674	  bp->b_dirt = CLEAN;
 22675	}
	
 22677	/*===========================================================================*
 22678	 *                              invalidate                                   *
 22679	 *===========================================================================*/
 22680	PUBLIC void invalidate(device)
 22681	dev_t device;                   /* устройство, блоки которого нужно очистить */
 22682	{
 22683	/* Удаление из кэша всех блоков, принадлежащих определенному устройству. */
 22684	
 22685	  register struct buf *bp;
 22686	
 22687	  for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++)
 22688	        if (bp->b_dev == device) bp->b_dev = NO_DEV;
 22689	}
	
 22691	/*===========================================================================*
 22692	 *                              flushall                                     *
 22693	 *===========================================================================*/
 22694	PUBLIC void flushall(dev)
 22695	dev_t dev;                      /* устройство, на которое осуществляется сброс */
 22696	{
 22697	/* Сброс всех блоков на одно устройство. */
 22698	
 22699	  register struct buf *bp;
 22700	  static struct buf *dirty[NR_BUFS];    /* статическая структура, не помещаемая в стек */
 22701	  int ndirty;
 22702	
 22703	  for (bp = &buf[0], ndirty = 0; bp < &buf[NR_BUFS]; bp++)
 22704	        if (bp->b_dirt == DIRTY && bp->b_dev == dev) dirty[ndirty++] = bp;
 22705	  rw_scattered(dev, dirty, ndirty, WRITING);
 22706	}
	
 22708	/*===========================================================================*
 22709	 *                              rw_scattered                                 *
 22710	 *===========================================================================*/
 22711	PUBLIC void rw_scattered(dev, bufq, bufqsize, rw_flag)
 22712	dev_t dev;                      /* главный-вспомогательный номер устройства */
 22713	struct buf **bufq;              /* указатель на массив буферов */
 22714	int bufqsize;                   /* число буферов */
 22715	int rw_flag;                    /* чтение или запись */
 22716	{
 22717	/* чтение с устройства или запись на устройство разрозненных данных. */
 22718	
 22719	  register struct buf *bp;
 22720	  int gap;
 22721	  register int i;
 22722	  register iovec_t *iop;
 22723	  static iovec_t iovec[NR_IOREQS];  /* статический массив, не помещаемый в стек */
 22724	  int j, r;
 22725	  int block_size;
 22726	
 22727	  block_size = get_block_size(dev);
 22728	
 22729	  /* сортировка методом Шелла буферов в b_blocknr. */
 22730	  gap = 1;
 22731	  do
 22732	        gap = 3 * gap + 1;
 22733	  while (gap <= bufqsize);
 22734	  while (gap != 1) {
 22735	        gap /= 3;
 22736	        for (j = gap; j < bufqsize; j++) {
 22737	                for (i = j - gap;
 22738	                     i >= 0 && bufq[i]->b_blocknr > bufq[i + gap]->b_blocknr;
 22739	                     i -= gap) {
 22740	                        bp = bufq[i];
 22741	                        bufq[i] = bufq[i + gap];
 22742	                        bufq[i + gap] = bp;
 22743	                }
 22744	        }
 22745	  }
 22746	
 22747	  /* Формирование вектора ввода-вывода и выполнение ввода-вывода. Результат dev_io – OK, если
 22748	   * все прошло успешно, иначе возврашается код первой ошибки при передаче.
 22749	   */  
 22750	  while (bufqsize > 0) {
 22751	        for (j = 0, iop = iovec; j < NR_IOREQS && j < bufqsize; j++, iop++) {
 22752	                bp = bufq[j];
 22753	                if (bp->b_blocknr != bufq[0]->b_blocknr + j) break;
 22754	                iop->iov_addr = (vir_bytes) bp->b_data;
 22755	                iop->iov_size = block_size;
 22756	        }
 22757	        r = dev_io(rw_flag == WRITING ? DEV_SCATTER :  DEV_GATHER,
 22758	                dev, FS_PROC_NR, iovec,
 22759	                (off_t) bufq[0]->b_blocknr * block_size, j, 0);
 22760	
 22761	        /* Сбор результатотв; dev_io указывает на первую ошибку, которая могла
 22762	         * произойти, однако нам важна ошибка при передаче первого блока.
 22763	         */
 22764	        for (i = 0, iop = iovec; i < j; i++, iop++) {
 22765	                bp = bufq[i];
 22766	                if (iop->iov_size != 0) {
 22767	                        /* Передача неудачна. Ошибка? Важная ли для нас? */
 22768	                        if (r != OK && i == 0) {
 22769	                                printf(
 22770	                                "fs:  I/O error on device %d/%d, block %lu\n",
 22771	                                        (dev>>MAJOR)&BYTE, (dev>>MINOR)&BYTE,
 22772	                                        bp->b_blocknr);
 22773	                                bp->b_dev = NO_DEV;     /* теперь блок недействителен */
 22774	                        }
 22775	                        break;
 22776	                }
 22777	                if (rw_flag == READING) {
 22778	                        bp->b_dev = dev;        /* блок действителен */
 22779	                        put_block(bp, PARTIAL_DATA_BLOCK);
 22780	                } else {
 22781	                        bp->b_dirt = CLEAN;
 22782	                }
 22783	        }
 22784	        bufq += i;
 22785	        bufqsize -= i;
 22786	        if (rw_flag == READING) {
 22787	                /* Не считывать больше данных, чем устройство собирается передать. 
 22788	                 * Освободить "излишки".
 22789	                 */
 22790	                while (bufqsize > 0) {
 22791	                        put_block(*bufq++, PARTIAL_DATA_BLOCK);
 22792	                        bufqsize--;
 22793	                }
 22794	        }
 22795	        if (rw_flag == WRITING && i == 0) {
 22796	                /* Операция не движется вперед, это означает, что мы зациклились.
 22797	                 * Если буферы не сбрасываются, они считаются модифицированными.
 22798	                 * Буферы, объявленные недействительными или удаленные из LRU-списка,
 22799	                 * теряются, однако это лучше, чем навсегда сохранять немодифицируемые блоки
 22800	                 */
 22801	                break;
 22802	        }
 22803	  }
 22804	}
	
 22806	/*===========================================================================*
 22807	 *                              rm_lru                                       *
 22808	 *===========================================================================*/
 22809	PRIVATE void rm_lru(bp)
 22810	struct buf *bp;
 22811	{
 22812	/* Удаление блока из LRU-цепочки. */
 22813	  struct buf *next_ptr, *prev_ptr;
 22814	
 22815	  bufs_in_use++;
 22816	  next_ptr = bp->b_next;        /* следующий в LRU-цепочке */
 22817	  prev_ptr = bp->b_prev;        /* предыдущий в LRU-цепочке */
 22818	  if (prev_ptr != NIL_BUF)
 22819	        prev_ptr->b_next = next_ptr;
 22820	  else
 22821	        front = next_ptr;       /* этот блок был в начале цепочки */
 22822	
 22823	  if (next_ptr != NIL_BUF)
 22824	        next_ptr->b_prev = prev_ptr;
 22825	  else
 22826	        rear = prev_ptr;        /* этот блок был в конце цепочки */
 22827	}



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/inode.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 22900	/* Этот файл управляет таблицей индексных узлов. В нем имеются процедуры выделения и
 22901	 * освобождения индексных узлов, их получения, стирания и освобождения, а также чтения
 22902	 * и записи на диск.
 22903	 *
 22904	 * Файл имеет следующие точки входа:
 22905	 *   get_inode:     поиск индексного узла в таблице; если поиск неудачен, считать
 22906	 *                  индексный узел
 22907	 *   put_inode:     указывает на то, что индексный узел больше не нужен в памяти
 22908	 *   alloc_inode:   выделение нового, неиспользуеамого индексного узла
 22909	 *   wipe_inode:    стирание некоторых полей нового индексного узла
 22910	 *   free_inode:    пометка индексного узла как доступного для нового файла
 22911	 *   update_times:  обновление atime, ctime и mtime
 22912	 *   rw_inode:      чтение блока с диска и извлечение индексного узла, либо запись индексного узла в блок
 22913	 *   old_icopy:     копирование во внутреннюю структуру и из нее индексного узла и индексного узла диска (V1.x)
 22914	 *   new_icopy:     копирование во внутреннюю структуру и из нее индексного узла и индексного узла диска (V2.x)
 22915	 *   dup_inode:     указывает, что кто-то еще использует запись индексного узла
 22916	 */
 22917	
 22918	#include "fs.h"
 22919	#include "buf.h"
 22920	#include "file.h"
 22921	#include "fproc.h"
 22922	#include "inode.h"
 22923	#include "super.h"
 22924	
 22925	FORWARD _PROTOTYPE( void old_icopy, (struct inode *rip, d1_inode *dip,
 22926	                                                int direction, int norm));
 22927	FORWARD _PROTOTYPE( void new_icopy, (struct inode *rip, d2_inode *dip,
 22928	                                                int direction, int norm));
 22929	
 22930	/*===========================================================================*
 22931	 *                              get_inode                                    *
 22932	 *===========================================================================*/
 22933	PUBLIC struct inode *get_inode(dev, numb)
 22934	dev_t dev;                      /* устройство, на котором находится индексный узел */
 22935	int numb;                       /* номер индексного узла */
 22936	{
 22937	/* Поиск записи в таблице индексных узлов, загрузка в нее указанного индексного узла и возврат указателя
 22938	 * на запись.  Если 'dev' == NO_DEV, возвращается свободная запись.
 22939	 */
 22940	
 22941	  register struct inode *rip, *xp;
 22942	
 22943	  /* Поиск в таблице индексных узлов записи (устройство, номер) и свободной записи. */
 22944	  xp = NIL_INODE;
 22945	  for (rip = &inode[0]; rip < &inode[NR_INODES]; rip++) {
 22946	        if (rip->i_count > 0) { /* поиск записи (устройство, номер) только среди используемых записей */
 22947	                if (rip->i_dev == dev && rip->i_num == numb) {
 22948	                        /* Это индексный узел, который мы ищем. */
 22949	                        rip->i_count++;
 22950	                        return(rip);    /* запись (устройство, номер) найдена */
 22951	                }
 22952	        } else {
 22953	                xp = rip;       /* запомнить эту свободную запись на будущее */
 22954	        }
 22955	  }
 22956	
 22957	  /* Желаемый индексный узел в настоящий момент не используется. Нашли ли мы свободную запись? */
 22958	  if (xp == NIL_INODE) {        /* Таблица индексных узлов целиком заполнена */
 22959	        err_code = ENFILE;
 22960	        return(NIL_INODE);
 22961	  }
 22962	
 22963	  /* Свободная запись для индексного узла выделена. Загрузить индексный узел в нее. */
 22964	  xp->i_dev = dev;
 22965	  xp->i_num = numb;
 22966	  xp->i_count = 1;
 22967	  if (dev != NO_DEV) rw_inode(xp, READING);     /* считывание индексного узла с диска */
 22968	  xp->i_update = 0;             /* все значения времени изначально актуальны */
 22969	
 22970	  return(xp);
 22971	}
	
 22973	/*===========================================================================*
 22974	 *                              put_inode                                    *
 22975	 *===========================================================================*/
 22976	PUBLIC void put_inode(rip)
 22977	register struct inode *rip;     /* указатель на освобождаемый индексный узел */
 22978	{
 22979	/* Вызывающий процесс больше не использует этот индексный узел. Если индексный узел никому не нужен,
 22980	 * немедленно записать его обратно на диск. Если у него нет связей, отбросить его и
 22981	 * поместить в пул свободных индексных узлов.
 22982	 */
 22983	
 22984	  if (rip == NIL_INODE) return; /* выполнить проверку здесь проще, чем в вызывающем процессе */
 22985	  if (--rip->i_count == 0) {    /* i_count == 0 означает, что никто не использует индексный узел */
 22986	        if (rip->i_nlinks == 0) {
 22987	                /* i_nlinks == 0 означает освободить индексный узел. */
 22988	                truncate(rip);  /* вернуть все дисковые блоки */
 22989	                rip->i_mode = I_NOT_ALLOC;      /* очистка поля I_TYPE */
 22990	                rip->i_dirt = DIRTY;
 22991	                free_inode(rip->i_dev, rip->i_num);
 22992	        } else {
 22993	                if (rip->i_pipe == I_PIPE) truncate(rip);
 22994	        }
 22995	        rip->i_pipe = NO_PIPE;  /* всегда следует очищать */
 22996	        if (rip->i_dirt == DIRTY) rw_inode(rip, WRITING);
 22997	  }
 22998	}
	
 23000	/*===========================================================================*
 23001	 *                              alloc_inode                                  *
 23002	 *===========================================================================*/
 23003	PUBLIC struct inode *alloc_inode(dev_t dev, mode_t bits)
 23004	{
 23005	/* Выделить свободный индексный узел на устройстве 'dev' и вернуть указатель на него. */
 23006	
 23007	  register struct inode *rip;
 23008	  register struct super_block *sp;
 23009	  int major, minor, inumb;
 23010	  bit_t b;
 23011	
 23012	  sp = get_super(dev);  /* получение указателя на суперблок */
 23013	  if (sp->s_rd_only) {  /* индексный узел невозможно выделить на устройстве только для чтения. */
 23014	        err_code = EROFS;
 23015	        return(NIL_INODE);
 23016	  }
 23017	
 23018	  /* Получение индексного узла из битовой карты. */
 23019	  b = alloc_bit(sp, IMAP, sp->s_isearch);
 23020	  if (b == NO_BIT) {
 23021	        err_code = ENFILE;
 23022	        major = (int) (sp->s_dev >> MAJOR) & BYTE;
 23023	        minor = (int) (sp->s_dev >> MINOR) & BYTE;
 23024	        printf("Out of i-nodes on %sdevice %d/%d\n",
 23025	                sp->s_dev == root_dev ? "root " :  "", major, minor);
 23026	        return(NIL_INODE);
 23027	  }
 23028	  sp->s_isearch = b;            /* в следующий раз начать здесь */
 23029	  inumb = (int) b;              /* будьте внимательны – не передайте unshort в качестве параметра */
 23030	
 23031	  /* Попытка получить запись в таблице индексных узлов. */
 23032	  if ((rip = get_inode(NO_DEV, inumb)) == NIL_INODE) {
 23033	        /* Невозможно выделить запись в таблице индексных узлов. Освободить только что выделенный индексный узел. */
 23034	        free_bit(sp, IMAP, b);
 23035	  } else {
 23036	        /* Запись индексного узла доступна. Помещение в нее только что выделенного индексного узла. */
 23037	        rip->i_mode = bits;             /* задание битов RWX */
 23038	        rip->i_nlinks = 0;              /* изначально связей */
 23039	        rip->i_uid = fp->fp_effuid;     /* uid файла принадлежит владельцу */
 23040	        rip->i_gid = fp->fp_effgid;     /* то же касается id группы */
 23041	        rip->i_dev = dev;               /* устройство, на котором находится индексный узел */
 23042	        rip->i_ndzones = sp->s_ndzones; /* число прямых зон */
 23043	        rip->i_nindirs = sp->s_nindirs; /* число косвенных зон на блок */
 23044	        rip->i_sp = sp;                 /* указатель на суперблок */
 23045	
 23046	        /* Неочищенные поля очищаются функцией wipe_inode(). Они были помещены
 23047	         * туда потому, что функции truncate() нужно очистить те же поля, если
 23048	         * оказывается, что при очистке файл открыт. Не повторяя один и тот же
 23049	         * код дважды, мы экономим место.
 23050	         */
 23051	        wipe_inode(rip);
 23052	  }
 23053	
 23054	  return(rip);
 23055	}
	
 23057	/*===========================================================================*
 23058	 *                              wipe_inode                                   *
 23059	 *===========================================================================*/
 23060	PUBLIC void wipe_inode(rip)
 23061	register struct inode *rip;     /* индексный узел для очистки */
 23062	{
 23063	/* Очистка некоторых полей индексного узла.  Эта функция вызывается из alloc_inode(),
 23064	 * когда нужно выделить новый индексный узел, и из функции truncate(), когда требуется
 23065	 * отбросить существующий индексный узел.
 23066	 */
 23067	
 23068	  register int i;
 23069	
 23070	  rip->i_size = 0;
 23071	  rip->i_update = ATIME | CTIME | MTIME;        /* обновить значения времени позже */
 23072	  rip->i_dirt = DIRTY;
 23073	  for (i = 0; i < V2_NR_TZONES; i++) rip->i_zone[i] = NO_ZONE;
 23074	}
	
 23076	/*===========================================================================*
 23077	 *                              free_inode                                   *
 23078	 *===========================================================================*/
 23079	PUBLIC void free_inode(dev, inumb)
 23080	dev_t dev;                      /* устройство, на котором расположен индексный узел */
 23081	ino_t inumb;                    /* номер освобождаемого индексного узла */
 23082	{
 23083	/* Возврат индексного узла в пул свободных индексных узлов. */
 23084	
 23085	  register struct super_block *sp;
 23086	  bit_t b;
 23087	
 23088	  /* Поиск подходящего суперблока. */
 23089	  sp = get_super(dev);
 23090	  if (inumb <= 0 || inumb > sp->s_ninodes) return;
 23091	  b = inumb;
 23092	  free_bit(sp, IMAP, b);
 23093	  if (b < sp->s_isearch) sp->s_isearch = b;
 23094	}
	
 23096	/*===========================================================================*
 23097	 *                              update_times                                 *
 23098	 *===========================================================================*/
 23099	PUBLIC void update_times(rip)
 23100	register struct inode *rip;     /* указатель на записываемый/считываемый индексный узел */
 23101	{
 23102	/* Стандарт требует реализации отдельных системных вызовов для изменения atime, ctime и
 23103	 * mtime. Поскольку для обновления значений времени требуется послать сообщение таймерному
 23104	 * заданию (затратное действие), необходимость обновления отмечается установкой битов в
 23105	 * переменной i_update. Когда вызов stat, fstat или sync завершается или освобождается индексный узел,
 23106	 * функция update_times() может быть вызвана для фактической установки времени.
 23107	 */
 23108	
 23109	  time_t cur_time;
 23110	  struct super_block *sp;
 23111	
 23112	  sp = rip->i_sp;               /* получение указателя на суперблок. */
 23113	  if (sp->s_rd_only) return;    /* не обновлять файловые системы только для чтения */
 23114	
 23115	  cur_time = clock_time();
 23116	  if (rip->i_update & ATIME) rip->i_atime = cur_time;
 23117	  if (rip->i_update & CTIME) rip->i_ctime = cur_time;
 23118	  if (rip->i_update & MTIME) rip->i_mtime = cur_time;
 23119	  rip->i_update = 0;            /* теперь значения времени актуальны  */
 23120	}
	
 23122	/*===========================================================================*
 23123	 *                              rw_inode                                     *
 23124	 *===========================================================================*/
 23125	PUBLIC void rw_inode(rip, rw_flag)
 23126	register struct inode *rip;     /* указатель на считываемый/записываемый индексный узел */
 23127	int rw_flag;                    /* чтение или запись */
 23128	{
 23129	/* Запись в таблице индексных узлов необходимо скопировать с диска или на диск. */
 23130	
 23131	  register struct buf *bp;
 23132	  register struct super_block *sp;
 23133	  d1_inode *dip;
 23134	  d2_inode *dip2;
 23135	  block_t b, offset;
 23136	
 23137	  /* Получение блока, в котором находится индексный узел. */
 23138	  sp = get_super(rip->i_dev);   /* получение указателя на суперблок */
 23139	  rip->i_sp = sp;               /* индексный узел должен содержать указатель на суперблок */
 23140	  offset = sp->s_imap_blocks + sp->s_zmap_blocks + 2;
 23141	  b = (block_t) (rip->i_num - 1)/sp->s_inodes_per_block + offset;
 23142	  bp = get_block(rip->i_dev, b, NORMAL);
 23143	  dip  = bp->b_v1_ino + (rip->i_num - 1) % V1_INODES_PER_BLOCK;
 23144	  dip2 = bp->b_v2_ino + (rip->i_num - 1) %
 23145	         V2_INODES_PER_BLOCK(sp->s_block_size);
 23146	
 23147	  /* Выполнение чтения или записи. */
 23148	  if (rw_flag == WRITING) {
 23149	        if (rip->i_update) update_times(rip);   /* значения времени необходимо обновить */
 23150	        if (sp->s_rd_only == FALSE) bp->b_dirt = DIRTY;
 23151	  }
 23152	
 23153	  /* Копирование индексного узла из блока диска во внутреннюю таблицу или наоборот. Если четвертый
 23154	   * параметр меньше FALSE, порядок следования байтов меняется.
 23155	   */
 23156	  if (sp->s_version == V1)
 23157	        old_icopy(rip, dip,  rw_flag, sp->s_native);
 23158	  else
 23159	        new_icopy(rip, dip2, rw_flag, sp->s_native);
 23160	  
 23161	  put_block(bp, INODE_BLOCK);
 23162	  rip->i_dirt = CLEAN;
 23163	}
	
 23165	/*===========================================================================*
 23166	 *                              old_icopy                                    *
 23167	 *===========================================================================*/
 23168	PRIVATE void old_icopy(rip, dip, direction, norm)
 23169	register struct inode *rip;     /* указатель на внутреннюю структуру индексного узла */
 23170	register d1_inode *dip;         /* указатель на структуру индексного узла d1_inode */
 23171	int direction;                  /* чтение с диска или запись на диск */
 23172	int norm;                       /* TRUE = не менять порядок следования байтов; FALSE = менять */
 23173	
 23174	{
 23175	/* Диск IBM V1.x, диск 68000 V1.x и оба типа дисков V2 имеют разные структуры индексных узлов.
 23176	 * При чтении и записи индексного узла эта процедура осуществляет преобразования, чтобы информация
 23177	 * в таблице индексных узлов не зависела от структуры дисков, с которых были считаны индексные узлы.
 23178	 * Процедура old_icopy выполняет копирование с дисков и на диски V1 .
 23179	 *
 23180	 */
 23181	
 23182	  int i;
 23183	
 23184	  if (direction == READING) {
 23185	 /* Копирование индексного узла V1.x во внутреннюю таблицу с изменением порядка следования байтов при необходимости. */
 23186	        rip->i_mode    = conv2(norm, (int) dip->d1_mode);
 23187	        rip->i_uid     = conv2(norm, (int) dip->d1_uid );
 23188	        rip->i_size    = conv4(norm,       dip->d1_size);
 23189	        rip->i_mtime   = conv4(norm,       dip->d1_mtime);
 23190	        rip->i_atime   = rip->i_mtime;
 23191	        rip->i_ctime   = rip->i_mtime;
 23192	        rip->i_nlinks  = dip->d1_nlinks;                /* 1 символ */
 23193	        rip->i_gid     = dip->d1_gid;                   /* 1 символ */
 23194	        rip->i_ndzones = V1_NR_DZONES;
 23195	        rip->i_nindirs = V1_INDIRECTS;
 23196	        for (i = 0; i < V1_NR_TZONES; i++)
 23197	                rip->i_zone[i] = conv2(norm, (int) dip->d1_zone[i]);
 23198	  } else {
 23199	        /* Копирование индексного узла V1.x на диск из внутренней таблицы. */
 23200	        dip->d1_mode   = conv2(norm, (int) rip->i_mode);
 23201	        dip->d1_uid    = conv2(norm, (int) rip->i_uid );
 23202	        dip->d1_size   = conv4(norm,       rip->i_size);
 23203	        dip->d1_mtime  = conv4(norm,       rip->i_mtime);
 23204	        dip->d1_nlinks = rip->i_nlinks;                 /* 1 символ */
 23205	        dip->d1_gid    = rip->i_gid;                    /* 1 символ */
 23206	        for (i = 0; i < V1_NR_TZONES; i++)
 23207	                dip->d1_zone[i] = conv2(norm, (int) rip->i_zone[i]);
 23208	  }
 23209	}
	
 23211	/*===========================================================================*
 23212	 *                              new_icopy                                    *
 23213	 *===========================================================================*/
 23214	PRIVATE void new_icopy(rip, dip, direction, norm)
 23215	register struct inode *rip;     /* указатель на внутреннюю структуру индексного узла */
 23216	register d2_inode *dip;         /* указатель на структуру d2_inode */
 23217	int direction;                  /* чтение с диска или запись на диск */
 23218	int norm;                       /* TRUE = не изменять порядок следования байтов; FALSE = изменить */
 23219	
 23220	{
 23221	/* То же, что и old_icopy, но копирование с диска и на диск со структурой V2. */
 23222	
 23223	  int i;
 23224	
 23225	  if (direction == READING) {
 23226	 /* Копирование индексного узла V2.x во внутреннюю таблицу с изменением порядка следования байтов при необходимости. */
 23227	        rip->i_mode    = conv2(norm,dip->d2_mode);
 23228	        rip->i_uid     = conv2(norm,dip->d2_uid);
 23229	        rip->i_nlinks  = conv2(norm,dip->d2_nlinks);
 23230	        rip->i_gid     = conv2(norm,dip->d2_gid);
 23231	        rip->i_size    = conv4(norm,dip->d2_size);
 23232	        rip->i_atime   = conv4(norm,dip->d2_atime);
 23233	        rip->i_ctime   = conv4(norm,dip->d2_ctime);
 23234	        rip->i_mtime   = conv4(norm,dip->d2_mtime);
 23235	        rip->i_ndzones = V2_NR_DZONES;
 23236	        rip->i_nindirs = V2_INDIRECTS(rip->i_sp->s_block_size);
 23237	        for (i = 0; i < V2_NR_TZONES; i++)
 23238	                rip->i_zone[i] = conv4(norm, (long) dip->d2_zone[i]);
 23239	  } else {
 23240	        /* Копирование индексного узла V2.x на диск из внутренней таблицы. */
 23241	        dip->d2_mode   = conv2(norm,rip->i_mode);
 23242	        dip->d2_uid    = conv2(norm,rip->i_uid);
 23243	        dip->d2_nlinks = conv2(norm,rip->i_nlinks);
 23244	        dip->d2_gid    = conv2(norm,rip->i_gid);
 23245	        dip->d2_size   = conv4(norm,rip->i_size);
 23246	        dip->d2_atime  = conv4(norm,rip->i_atime);
 23247	        dip->d2_ctime  = conv4(norm,rip->i_ctime);
 23248	        dip->d2_mtime  = conv4(norm,rip->i_mtime);
 23249	        for (i = 0; i < V2_NR_TZONES; i++)
 23250	                dip->d2_zone[i] = conv4(norm, (long) rip->i_zone[i]);
 23251	  }
 23252	}
	
 23254	/*===========================================================================*
 23255	 *                              dup_inode                                    *
 23256	 *===========================================================================*/
 23257	PUBLIC void dup_inode(ip)
 23258	struct inode *ip;               /* дублируемый индексный узел. */
 23259	{
 23260	/* Эта процедура – упрощенная форма get_inode() для случая, когда указатель на
 23261	 * индексный узел уже известен.
 23262	 */
 23263	
 23264	  ip->i_count++;
 23265	}





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/super.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 23300	/* Этот файл управляет таблицей суперблоков и связанными с ней структурами данных,
 23301	 * а именно битовыми картами, отмечающими свободные и выделенные зоны и индексные узлы. Когда
 23302	 * требуется выделить новый индексный узел или зону, поиск свободной записи осуществляется в
 23303	 * соответствующей битовой карте.
 23304	 *
 23305	 * Этот файл имеет следующие точки входа:
 23306	 *   alloc_bit:        поиск зоны или индексного узла для выделения
 23307	 *   free_bit:         указывает, что зона или индексный узел свободен и может быть выделен
 23308	 *   get_super:        поиск устройства в таблице суперблоков
 23309	 *   mounted:          определяет, находится ли индексный узел на монтированной или корневой файловой системе
 23310	 *   read_super:       чтение суперблока
 23311	 */
 23312	
 23313	#include "fs.h"
 23314	#include <string.h>
 23315	#include <minix/com.h>
 23316	#include "buf.h"
 23317	#include "inode.h"
 23318	#include "super.h"
 23319	#include "const.h"
 23320	
 23321	/*===========================================================================*
 23322	 *                              alloc_bit                                    *
 23323	 *===========================================================================*/
 23324	PUBLIC bit_t alloc_bit(sp, map, origin)
 23325	struct super_block *sp;         /* файловая система, в которой происходит выделение */
 23326	int map;                        /* IMAP (карта индексных узлов) иди ZMAP (карта зон) */
 23327	bit_t origin;                   /* номер бита, с которого нужно начинать поиск */
 23328	{
 23329	/* Выделение бита в битовой карте и возврат его номера. */
 23330	
 23331	  block_t start_block;          /* первый блок битов */
 23332	  bit_t map_bits;               /* число битов в битовой карте */
 23333	  unsigned bit_blocks;          /* число блоков в битовой карте */
 23334	  unsigned block, word, bcount;
 23335	  struct buf *bp;
 23336	  bitchunk_t *wptr, *wlim, k;
 23337	  bit_t i, b;
 23338	
 23339	  if (sp->s_rd_only)
 23340	        panic(__FILE__,"can't allocate bit on read-only filesys.", NO_NUM);
 23341	
 23342	  if (map == IMAP) {
 23343	        start_block = START_BLOCK;
 23344	        map_bits = sp->s_ninodes + 1;
 23345	        bit_blocks = sp->s_imap_blocks;
 23346	  } else {
 23347	        start_block = START_BLOCK + sp->s_imap_blocks;
 23348	        map_bits = sp->s_zones - (sp->s_firstdatazone - 1);
 23349	        bit_blocks = sp->s_zmap_blocks;
 23350	  }
 23351	
 23352	  /* Определение места начала поиска бита (зависит от 'origin'). */
 23353	  if (origin >= map_bits) origin = 0;   /* для надежности */
 23354	
 23355	  /* Переход в место начала поиска. */
 23356	  block = origin / FS_BITS_PER_BLOCK(sp->s_block_size);
 23357	  word = (origin % FS_BITS_PER_BLOCK(sp->s_block_size)) / FS_BITCHUNK_BITS;
 23358	
 23359	  /* Проход по всем блокам плюс 1, так как мы начинаем в середине. */
 23360	  bcount = bit_blocks + 1;
 23361	  do {
 23362	        bp = get_block(sp->s_dev, start_block + block, NORMAL);
 23363	        wlim = &bp->b_bitmap[FS_BITMAP_CHUNKS(sp->s_block_size)];
 23364	
 23365	        /* Проход по словам блока. */
 23366	        for (wptr = &bp->b_bitmap[word]; wptr < wlim; wptr++) {
 23367	
 23368	                /* Содержит ли это слово свободный бит? */
 23369	                if (*wptr == (bitchunk_t) ~0) continue;
 23370	
 23371	                /* Поиск и выделение свободного бита. */
 23372	                k = conv2(sp->s_native, (int) *wptr);
 23373	                for (i = 0; (k & (1 << i)) != 0; ++i) {}
 23374	
 23375	                /* Номер бита, считая от начала битовой карты. */
 23376	                b = ((bit_t) block * FS_BITS_PER_BLOCK(sp->s_block_size))
 23377	                    + (wptr - &bp->b_bitmap[0]) * FS_BITCHUNK_BITS
 23378	                    + i;
 23379	
 23380	                /* Не выделять биты за концом битовой карты. */
 23381	                if (b >= map_bits) break;
 23382	
 23383	                /* Выделение и возврат номера бита. */
 23384	                k |= 1 << i;
 23385	                *wptr = conv2(sp->s_native, (int) k);
 23386	                bp->b_dirt = DIRTY;
 23387	                put_block(bp, MAP_BLOCK);
 23388	                return(b);
 23389	        }
 23390	        put_block(bp, MAP_BLOCK);
 23391	        if (++block >= bit_blocks) block = 0;   /* последний блок, переход в начало */
 23392	        word = 0;
 23393	  } while (--bcount > 0);
 23394	  return(NO_BIT);               /* не удалось выделить бит */
 23395	}
	
 23397	/*===========================================================================*
 23398	 *                              free_bit                                     *
 23399	 *===========================================================================*/
 23400	PUBLIC void free_bit(sp, map, bit_returned)
 23401	struct super_block *sp;         /* обрабатываемая файловая система */
 23402	int map;                        /* IMAP (карта индексных узлов) иди ZMAP (карта зон) */
 23403	bit_t bit_returned;             /* номер бита, который нужно вставить в карту  */
 23404	{
 23405	/* Вернуть зону или индексный узел, сбросив ее/его бит в битовой карте. */
 23406	
 23407	  unsigned block, word, bit;
 23408	  struct buf *bp;
 23409	  bitchunk_t k, mask;
 23410	  block_t start_block;
 23411	
 23412	  if (sp->s_rd_only)
 23413	        panic(__FILE__,"can't free bit on read-only filesys.", NO_NUM);
 23414	
 23415	  if (map == IMAP) {
 23416	        start_block = START_BLOCK;
 23417	  } else {
 23418	        start_block = START_BLOCK + sp->s_imap_blocks;
 23419	  }
 23420	  block = bit_returned / FS_BITS_PER_BLOCK(sp->s_block_size);
 23421	  word = (bit_returned % FS_BITS_PER_BLOCK(sp->s_block_size))
 23422	         / FS_BITCHUNK_BITS;
 23423	
 23424	  bit = bit_returned % FS_BITCHUNK_BITS;
 23425	  mask = 1 << bit;
 23426	
 23427	  bp = get_block(sp->s_dev, start_block + block, NORMAL);
 23428	
 23429	  k = conv2(sp->s_native, (int) bp->b_bitmap[word]);
 23430	  if (!(k & mask)) {
 23431	        panic(__FILE__,map == IMAP ? "tried to free unused inode" : 
 23432	              "tried to free unused block", NO_NUM);
 23433	  }
 23434	
 23435	  k &= ~mask;
 23436	  bp->b_bitmap[word] = conv2(sp->s_native, (int) k);
 23437	  bp->b_dirt = DIRTY;
 23438	
 23439	  put_block(bp, MAP_BLOCK);
 23440	}
	
 23442	/*===========================================================================*
 23443	 *                              get_super                                    *
 23444	 *===========================================================================*/
 23445	PUBLIC struct super_block *get_super(dev)
 23446	dev_t dev;                      /* номер устройства, суперблок которого мы ищем */
 23447	{
 23448	/* Поиск устройства в таблице суперблоков. Предполагается, что оно в ней присутствует. */
 23449	
 23450	  register struct super_block *sp;
 23451	
 23452	  if (dev == NO_DEV)
 23453	        panic(__FILE__,"request for super_block of NO_DEV", NO_NUM);
 23454	
 23455	  for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
 23456	        if (sp->s_dev == dev) return(sp);
 23457	
 23458	  /* Поиск неудачен. Где-то есть ошибка. */
 23459	  panic(__FILE__,"can't find superblock for device (in decimal)", (int) dev);
 23460	
 23461	  return(NIL_SUPER);            /* соответствие компилятору и стандарту */
 23462	}
	
 23464	/*===========================================================================*
 23465	 *                              get_block_size                               *
 23466	 *===========================================================================*/
 23467	PUBLIC int get_block_size(dev_t dev)
 23468	{
 23469	/* Поиск этого устройства в таблице суперблоков. */
 23470	
 23471	  register struct super_block *sp;
 23472	
 23473	  if (dev == NO_DEV)
 23474	        panic(__FILE__,"request for block size of NO_DEV", NO_NUM);
 23475	
 23476	  for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) {
 23477	        if (sp->s_dev == dev) {
 23478	                return(sp->s_block_size);
 23479	        }
 23480	  }
 23481	
 23482	  /* Монтированные файловые системы отсутствуют? Используем этот размер блока. */
 23483	  return MIN_BLOCK_SIZE;
 23484	}
	
 23486	/*===========================================================================*
 23487	 *                              mounted                                      *
 23488	 *===========================================================================*/
 23489	PUBLIC int mounted(rip)
 23490	register struct inode *rip;     /* указатель на индексный узел */
 23491	{
 23492	/* Определение, на какой файловой системе находится данный индексный узел: монтированной или корневой
 23493	
 23494	  register struct super_block *sp;
 23495	  register dev_t dev;
 23496	
 23497	  dev = (dev_t) rip->i_zone[0];
 23498	  if (dev == root_dev) return(TRUE);    /* индексный узел на корневой файловой системе */
 23499	
 23500	  for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
 23501	        if (sp->s_dev == dev) return(TRUE);
 23502	
 23503	  return(FALSE);
 23504	}
	
 23506	/*===========================================================================*
 23507	 *                              read_super                                   *
 23508	 *===========================================================================*/
 23509	PUBLIC int read_super(sp)
 23510	register struct super_block *sp; /* указатель на суперблок */
 23511	{
 23512	/* Чтение суперблока. */
 23513	  dev_t dev;
 23514	  int magic;
 23515	  int version, native, r;
 23516	  static char sbbuf[MIN_BLOCK_SIZE];
 23517	
 23518	  dev = sp->s_dev;              /* сохранение устройства (будет перезаписано copy) */
 23519	  if (dev == NO_DEV)
 23520	        panic(__FILE__,"request for super_block of NO_DEV", NO_NUM);
 23521	  r = dev_io(DEV_READ, dev, FS_PROC_NR,
 23522	        sbbuf, SUPER_BLOCK_BYTES, MIN_BLOCK_SIZE, 0);
 23523	  if (r != MIN_BLOCK_SIZE) {
 23524	        return EINVAL;
 23525	  }
 23526	  memcpy(sp, sbbuf, sizeof(*sp));
 23527	  sp->s_dev = NO_DEV;           /* восстановить позже */
 23528	  magic = sp->s_magic;          /* определяет тип файловой системы */
 23529	
 23530	  /* Получение версии и типа файловой системы. */
 23531	  if (magic == SUPER_MAGIC || magic == conv2(BYTE_SWAP, SUPER_MAGIC)) {
 23532	        version = V1;
 23533	        native  = (magic == SUPER_MAGIC);
 23534	  } else if (magic == SUPER_V2 || magic == conv2(BYTE_SWAP, SUPER_V2)) {
 23535	        version = V2;
 23536	        native  = (magic == SUPER_V2);
 23537	  } else if (magic == SUPER_V3) {
 23538	        version = V3;
 23539	        native = 1;
 23540	  } else {
 23541	        return(EINVAL);
 23542	  }
 23543	
 23544	  /* Если суперблок имеет неправильный порядок следования байтов, изменить порядок; магическое число
 23545	   * не требует преобразования. */
 23546	  sp->s_ninodes =       conv4(native, sp->s_ninodes);
 23547	  sp->s_nzones =        conv2(native, (int) sp->s_nzones);
 23548	  sp->s_imap_blocks =   conv2(native, (int) sp->s_imap_blocks);
 23549	  sp->s_zmap_blocks =   conv2(native, (int) sp->s_zmap_blocks);
 23550	  sp->s_firstdatazone = conv2(native, (int) sp->s_firstdatazone);
 23551	  sp->s_log_zone_size = conv2(native, (int) sp->s_log_zone_size);
 23552	  sp->s_max_size =      conv4(native, sp->s_max_size);
 23553	  sp->s_zones =         conv4(native, sp->s_zones);
 23554	
 23555	  /* В V1 размер устройства хранился в переменной s_nzones типа short, что ограничивало
 23556	   * число зон устройства до 32K. В V2 размер устройства изменили на long. Тем не менее,
 23557	   * просто изменить тип s_nzones недостаточно, так как положение s_magic в суперблоке
 23558	   * файловых систем V1 и V2 неодинаково, а определить, какой из этих типов имеет новая
 23559	   * смонтированная файловая система, невозможно. Для решения проблемы была введена новая
 23560	   * переменная s_zones, в которую копируется размер устройства.
 23561	   *
 23562	   * Вычисление нескольких других чисел, зависящих от версии, чтобы скрыть некоторые
 23563	   * различия.
 23564	   *
 23565	   */
 23566	  if (version == V1) {
 23567	        sp->s_block_size = STATIC_BLOCK_SIZE;
 23568	        sp->s_zones = sp->s_nzones;     /* эта копия нужна только V1 */
 23569	        sp->s_inodes_per_block = V1_INODES_PER_BLOCK;
 23570	        sp->s_ndzones = V1_NR_DZONES;
 23571	        sp->s_nindirs = V1_INDIRECTS;
 23572	  } else {
 23573	        if (version == V2)
 23574	                sp->s_block_size = STATIC_BLOCK_SIZE;
 23575	        if (sp->s_block_size < MIN_BLOCK_SIZE)
 23576	                return EINVAL;
 23577	        sp->s_inodes_per_block = V2_INODES_PER_BLOCK(sp->s_block_size);
 23578	        sp->s_ndzones = V2_NR_DZONES;
 23579	        sp->s_nindirs = V2_INDIRECTS(sp->s_block_size);
 23580	  }
 23581	
 23582	  if (sp->s_block_size < MIN_BLOCK_SIZE) {
 23583	        return EINVAL;
 23584	  }
 23585	  if (sp->s_block_size > MAX_BLOCK_SIZE) {
 23586	        printf("Filesystem block size is %d kB; maximum filesystem\n"
 23587	        "block size is %d kB. This limit can be increased by recompiling.\n",
 23588	        sp->s_block_size/1024, MAX_BLOCK_SIZE/1024);
 23589	        return EINVAL;
 23590	  }
 23591	  if ((sp->s_block_size % 512) != 0) {
 23592	        return EINVAL;
 23593	  }
 23594	  if (SUPER_SIZE > sp->s_block_size) {
 23595	        return EINVAL;
 23596	  }
 23597	  if ((sp->s_block_size % V2_INODE_SIZE) != 0 ||
 23598	     (sp->s_block_size % V1_INODE_SIZE) != 0) {
 23599	        return EINVAL;
 23600	  }
 23601	
 23602	  sp->s_isearch = 0;            /* поиск индексного узла начинается с 0 */
 23603	  sp->s_zsearch = 0;            /* поиск зоны начинается с 0 */
 23604	  sp->s_version = version;
 23605	  sp->s_native  = native;
 23606	
 23607	  /* Несколько простых проверок суперблока. */
 23608	  if (sp->s_imap_blocks < 1 || sp->s_zmap_blocks < 1
 23609	                                || sp->s_ninodes < 1 || sp->s_zones < 1
 23610	                                || (unsigned) sp->s_log_zone_size > 4) {
 23611	        printf("not enough imap or zone map blocks, \n");
 23612	        printf("or not enough inodes, or not enough zones, "
 23613	                "or zone size too large\n");
 23614	        return(EINVAL);
 23615	  }
 23616	  sp->s_dev = dev;              /* восстановление номера устройства */
 23617	  return(OK);
 23618	}


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/filedes.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 23700	/* Этот файл содержит процедуры, манипулирующие дескрипторами файлов.
 23701	 *
 23702	 * В файле имеются следующие точки входа:
 23703	 *   get_fd:     поиск свободного дескриптора файла и освобождение записей filp
 23704	 *   get_filp:   поиск в записи filp заданного дескриптора файла
 23705	 *   find_filp:  поиск записи filp, указывающей на заданный индексный узел
 23706	 */
 23707	
 23708	#include "fs.h"
 23709	#include "file.h"
 23710	#include "fproc.h"
 23711	#include "inode.h"
 23712	
 23713	/*===========================================================================*
 23714	 *                              get_fd                                       *
 23715	 *===========================================================================*/
 23716	PUBLIC int get_fd(int start, mode_t bits, int *k, struct filp **fpt)
 23717	{
 23718	/* Поиск свободного дескриптора файла и освобождение записи filp. В последней заполняется 
 23719	 * слово режима, однако пока не одну из них не следует занимать, поскольку функции и creat()
 23720	 * могут завершиться неудачно.
 23721	 */
 23722	
 23723	  register struct filp *f;
 23724	  register int i;
 23725	
 23726	  *k = -1;                      /* нам необходимо определить, найден ли дескриптор файла */
 23727	
 23728	  /* Поиск свободного дескриптора файла в таблице fp_filp. */
 23729	  for (i = start; i < OPEN_MAX; i++) {
 23730	        if (fp->fp_filp[i] == NIL_FILP) {
 23731	                /* Дескриптор файла обнаружен. */
 23732	                *k = i;
 23733	                break;
 23734	        }
 23735	  }
 23736	
 23737	  /* Проверка, найден ли дескриптор файла. */
 23738	  if (*k < 0) return(EMFILE);   /* вот почему мы инициализировани k значением -1 */
 23739	
 23740	  /* Теперь, когда дескриптор файла найден, поиск свободной записи filp. */
 23741	  for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
 23742	        if (f->filp_count == 0) {
 23743	                f->filp_mode = bits;
 23744	                f->filp_pos = 0L;
 23745	                f->filp_selectors = 0;
 23746	                f->filp_select_ops = 0;
 23747	                f->filp_pipe_select_ops = 0;
 23748	                f->filp_flags = 0;
 23749	                *fpt = f;
 23750	                return(OK);
 23751	        }
 23752	  }
 23753	
 23754	  /* Если управление передается сюда, таблица filp целиком заполнена. Информировать об этом. */
 23755	  return(ENFILE);
 23756	}
	
 23758	/*===========================================================================*
 23759	 *                              get_filp                                     *
 23760	 *===========================================================================*/
 23761	PUBLIC struct filp *get_filp(fild)
 23762	int fild;                       /* дескриптор файла */
 23763	{
 23764	/* Проверка, указывает ли 'fild' на допустимый дескриптор файла. Если да, вернуть указатель filp. */
 23765	
 23766	  err_code = EBADF;
 23767	  if (fild < 0 || fild >= OPEN_MAX ) return(NIL_FILP);
 23768	  return(fp->fp_filp[fild]);    /* may also be NIL_FILP */
 23769	}
	
 23771	/*===========================================================================*
 23772	 *                              find_filp                                    *
 23773	 *===========================================================================*/
 23774	PUBLIC struct filp *find_filp(register struct inode *rip, mode_t bits)
 23775	{
 23776	/* Поиск записи filp, указывающей на индексный узел 'rip', так как задает бит режима 'bits'.
 23777	 * Используется для того, чтобы определить, нужны ли каким-либо процессам концы канала,
 23778	 * а также при открытии FIFO-списка для поиска партнеров для совместного использования
 23779	 * поля filp.
 23780	 * Как и в 'get_fd', здесь выполняется линейный поиск в таблице filp.
 23781	 */
 23782	
 23783	  register struct filp *f;
 23784	
 23785	  for (f = &filp[0]; f < &filp[NR_FILPS]; f++) {
 23786	        if (f->filp_count != 0 && f->filp_ino == rip && (f->filp_mode & bits)){
 23787	                return(f);
 23788	        }
 23789	  }
 23790	
 23791	  /* Если управление передается сюда, запись filp не найдена. Информировать об этом */
 23792	  return(NIL_FILP);
 23793	}


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/lock.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 23800	/* Этот файл обрабатывает добровольную блокировку файлов, требуемую стандартом POSIX.
 23801	 *
 23802	 * Файл имеет следующие точки входа:
 23803	 *   lock_op:      выполнение операций блокировки для системного вызова FCNTL
 23804	 *   lock_revive:  восстановление процесса после снятия блокировки
 23805	 */
 23806	
 23807	#include "fs.h"
 23808	#include <minix/com.h>
 23809	#include <fcntl.h>
 23810	#include <unistd.h>
 23811	#include "file.h"
 23812	#include "fproc.h"
 23813	#include "inode.h"
 23814	#include "lock.h"
 23815	#include "param.h"
 23816	
 23817	/*===========================================================================*
 23818	 *                              lock_op                                      *
 23819	 *===========================================================================*/
 23820	PUBLIC int lock_op(f, req)
 23821	struct filp *f;
 23822	int req;                        /* F_SETLK или F_SETLKW */
 23823	{
 23824	/* выполнение добровольной блокировки, требуемой POSIX. */
 23825	
 23826	  int r, ltype, i, conflict = 0, unlocking = 0;
 23827	  mode_t mo;
 23828	  off_t first, last;
 23829	  struct flock flock;
 23830	  vir_bytes user_flock;
 23831	  struct file_lock *flp, *flp2, *empty;
 23832	
 23833	  /* копирование структуры flock из пространства пользователя. */
 23834	  user_flock = (vir_bytes) m_in.name1;
 23835	  r = sys_datacopy(who, (vir_bytes) user_flock,
 23836	        FS_PROC_NR, (vir_bytes) &flock, (phys_bytes) sizeof(flock));
 23837	  if (r != OK) return(EINVAL);
 23838	
 23839	  /* несколько проверок на ошибки. */
 23840	  ltype = flock.l_type;
 23841	  mo = f->filp_mode;
 23842	  if (ltype != F_UNLCK && ltype != F_RDLCK && ltype != F_WRLCK) return(EINVAL);
 23843	  if (req == F_GETLK && ltype == F_UNLCK) return(EINVAL);
 23844	  if ( (f->filp_ino->i_mode & I_TYPE) != I_REGULAR) return(EINVAL);
 23845	  if (req != F_GETLK && ltype == F_RDLCK && (mo & R_BIT) == 0) return(EBADF);
 23846	  if (req != F_GETLK && ltype == F_WRLCK && (mo & W_BIT) == 0) return(EBADF);
 23847	
 23848	  /* Вычисление первого и последнего байтов в области блокировки. */
 23849	  switch (flock.l_whence) {
 23850	        case SEEK_SET:   first = 0; break;
 23851	        case SEEK_CUR:   first = f->filp_pos; break;
 23852	        case SEEK_END:   first = f->filp_ino->i_size; break;
 23853	        default:         return(EINVAL);
 23854	  }
 23855	  /* Проверка переполнения. */
 23856	  if (((long)flock.l_start > 0) && ((first + flock.l_start) < first))
 23857	        return(EINVAL);
 23858	  if (((long)flock.l_start < 0) && ((first + flock.l_start) > first))
 23859	        return(EINVAL);
 23860	  first = first + flock.l_start;
 23861	  last = first + flock.l_len - 1;
 23862	  if (flock.l_len == 0) last = MAX_FILE_POS;
 23863	  if (last < first) return(EINVAL);
 23864	
 23865	  /* Проверка конфликтов с существующими блокировками. */
 23866	  empty = (struct file_lock *) 0;
 23867	  for (flp = &file_lock[0]; flp < & file_lock[NR_LOCKS]; flp++) {
 23868	        if (flp->lock_type == 0) {
 23869	                if (empty == (struct file_lock *) 0) empty = flp;
 23870	                continue;       /* 0 означает неиспользуемую запись */
 23871	        }
 23872	        if (flp->lock_inode != f->filp_ino) continue;   /* другой файл */
 23873	        if (last < flp->lock_first) continue;   /* новый впереди */
 23874	        if (first > flp->lock_last) continue;   /* новый следом */
 23875	        if (ltype == F_RDLCK && flp->lock_type == F_RDLCK) continue;
 23876	        if (ltype != F_UNLCK && flp->lock_pid == fp->fp_pid) continue;
 23877	  
 23878	        /* Возможно наличие конфликта. Обработать его. */
 23879	        conflict = 1;
 23880	        if (req == F_GETLK) break;
 23881	
 23882	        /* Если была попытка блокировки, она только что завершилась неудачно. */
 23883	        if (ltype == F_RDLCK || ltype == F_WRLCK) {
 23884	                if (req == F_SETLK) {
 23885	                        /* Для F_SETLK просто сообщить об ошибке. */
 23886	                        return(EAGAIN);
 23887	                } else {
 23888	                        /* Для F_SETLKW приостановить процесс. */
 23889	                        suspend(XLOCK);
 23890	                        return(SUSPEND);
 23891	                }
 23892	        }
 23893	
 23894	        /* Мы снимаем блокировку и обнаружили перекрытие. */
 23895	        unlocking = 1;
 23896	        if (first <= flp->lock_first && last >= flp->lock_last) {
 23897	                flp->lock_type = 0;     /* пометить запись как неиспользуемую */
 23898	                nr_locks--;             /* теперь число блокировок на 1 меньше */
 23899	                continue;
 23900	        }
 23901	
 23902	        /* часть блокированной области разблокирована. */
 23903	        if (first <= flp->lock_first) {
 23904	                flp->lock_first = last + 1;
 23905	                continue;
 23906	        }
 23907	
 23908	        if (last >= flp->lock_last) {
 23909	                flp->lock_last = first - 1;
 23910	                continue;
 23911	        }
 23912	        
 23913	        /* Неудача: блокированная область разделена надвое из-за разблокирования посередине. */
 23914	        if (nr_locks == NR_LOCKS) return(ENOLCK);
 23915	        for (i = 0; i < NR_LOCKS; i++)
 23916	                if (file_lock[i].lock_type == 0) break;
 23917	        flp2 = &file_lock[i];
 23918	        flp2->lock_type = flp->lock_type;
 23919	        flp2->lock_pid = flp->lock_pid;
 23920	        flp2->lock_inode = flp->lock_inode;
 23921	        flp2->lock_first = last + 1;
 23922	        flp2->lock_last = flp->lock_last;
 23923	        flp->lock_last = first - 1;
 23924	        nr_locks++;
 23925	  }
 23926	  if (unlocking) lock_revive();
 23927	
 23928	  if (req == F_GETLK) {
 23929	        if (conflict) {
 23930	                /* GETLK и конфликт. Информирование о конфликтной блокировке. */
 23931	                flock.l_type = flp->lock_type;
 23932	                flock.l_whence = SEEK_SET;
 23933	                flock.l_start = flp->lock_first;
 23934	                flock.l_len = flp->lock_last - flp->lock_first + 1;
 23935	                flock.l_pid = flp->lock_pid;
 23936	
 23937	        } else {
 23938	                /* GETLK и отсутствие конфликта. */
 23939	                flock.l_type = F_UNLCK;
 23940	        }
 23941	
 23942	        /* Копирование структуры flock обратно в вызывающий процесс. */
 23943	        r = sys_datacopy(FS_PROC_NR, (vir_bytes) &flock,
 23944	                who, (vir_bytes) user_flock, (phys_bytes) sizeof(flock));
 23945	        return(r);
 23946	  }
 23947	
 23948	  if (ltype == F_UNLCK) return(OK);     /* область разблокирована, других блокировок на ней нет */
 23949	
 23950	  /* Конфликта нет. При наличии места сохранение новой блокировки в таблице. */
 23951	  if (empty == (struct file_lock *) 0) return(ENOLCK);  /* таблица заполнена */
 23952	  empty->lock_type = ltype;
 23953	  empty->lock_pid = fp->fp_pid;
 23954	  empty->lock_inode = f->filp_ino;
 23955	  empty->lock_first = first;
 23956	  empty->lock_last = last;
 23957	  nr_locks++;
 23958	  return(OK);
 23959	}
	
 23961	/*===========================================================================*
 23962	 *                              lock_revive                                  *
 23963	 *===========================================================================*/
 23964	PUBLIC void lock_revive()
 23965	{
 23966	/* Поиск всех процессов, ожидающих любых видов блокировки, и их восстановление.
 23967	 * Процессы, оставшиеся блокированными, заблокируются снова, как только будут запущены,
 23968	 * а остальные завершат работу. Эта стратегия – компромисс между пространством и скоростью.
 23969	 * Чтобы выяснить, какие процессы нужно разблокировать, потребуется дополнительный
 23970	 * код, и единственным выигрышем здесь будет производительность, причем в крайне редких случаях
 23971	 * (а именно, когда кто-то действительно пользовался блокировкой).
 23972	 *
 23973	 */
 23974	
 23975	  int task;
 23976	  struct fproc *fptr;
 23977	
 23978	  for (fptr = &fproc[INIT_PROC_NR + 1]; fptr < &fproc[NR_PROCS]; fptr++){
 23979	        task = -fptr->fp_task;
 23980	        if (fptr->fp_suspended == SUSPENDED && task == XLOCK) {
 23981	                revive( (int) (fptr - fproc), 0);
 23982	        }
 23983	  }
 23984	}


++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/main.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 24000	/* Этот файл содержит главную программу файловой системы. Он включает в себя цикл,
 24001	 * принимающий сообщения с запросами, выполняющий работу и отправляющий ответы.
 24002	 *
 24003	 *
 24004	 * Файл имеет следующие точки входа: 
 24005	 *   main:       главная программа файловой системы
 24006	 *   reply:      отправка сообщения процессу по завершении работы
 24007	 *
 24008	 */
 24009	
 24010	struct super_block;             /* файл proto.h должен знать это */
 24011	
 24012	#include "fs.h"
 24013	#include <fcntl.h>
 24014	#include <string.h>
 24015	#include <stdio.h>
 24016	#include <signal.h>
 24017	#include <stdlib.h>
 24018	#include <sys/ioc_memory.h>
 24019	#include <sys/svrctl.h>
 24020	#include <minix/callnr.h>
 24021	#include <minix/com.h>
 24022	#include <minix/keymap.h>
 24023	#include <minix/const.h>
 24024	#include "buf.h"
 24025	#include "file.h"
 24026	#include "fproc.h"
 24027	#include "inode.h"
 24028	#include "param.h"
 24029	#include "super.h"
 24030	
 24031	FORWARD _PROTOTYPE( void fs_init, (void)                                );
 24032	FORWARD _PROTOTYPE( int igetenv, (char *var, int optional)              );
 24033	FORWARD _PROTOTYPE( void get_work, (void)                               );
 24034	FORWARD _PROTOTYPE( void load_ram, (void)                               );
 24035	FORWARD _PROTOTYPE( void load_super, (Dev_t super_dev)                  );
 24036	
 24037	/*===========================================================================*
 24038	 *                              main                                         *
 24039	 *===========================================================================*/
 24040	PUBLIC int main()
 24041	{
 24042	/* Главная программа файловой системы. Главный цикл включает в себя три основных
 24043	 * действия: получение новой работы, ее выполнение и отправку ответа. Цикл бесконечен
 24044	 * и выполняется до тех пор, пока работает файловая система.
 24045	 */
 24046	  sigset_t sigset;
 24047	  int error;
 24048	
 24049	  fs_init();
 24050	
 24051	  /* Главный цикл, принимающий запросы, обрабатывающий их и посылающий ответы. */
 24052	  while (TRUE) {
 24053	        get_work();             /* устанавливает процесс и номер вызова */
 24054	
 24055	        fp = &fproc[who];       /* указатель на структуру таблицы процессов */
 24056	        super_user = (fp->fp_effuid == SU_UID ? TRUE :  FALSE);   /* su? */
 24057	
 24058	        /* Сначала проверяем специальные управляющие сообщения. */
 24059	        if (call_nr == SYS_SIG) { 
 24060	                sigset = m_in.NOTIFY_ARG;
 24061	                if (sigismember(&sigset, SIGKSTOP)) {
 24062	                        do_sync();
 24063	                        sys_exit(0);            /* никогда не возвращается */
 24064	                }
 24065	        } else if (call_nr == SYN_ALARM) {
 24066	                /* Запрос не пользовательский; истек один из наших таймеров, 
 24067	                 * теперь таймер требуется только для select(). Проверить его.
 24068	                 */
 24069	                fs_expire_timers(m_in.NOTIFY_TIMESTAMP);
 24070	        } else if ((call_nr & NOTIFY_MESSAGE)) {
 24071	                /* Устройство информирует нас о событии. */
 24072	                dev_status(&m_in);
 24073	        } else {
 24074	                /* Вызов внутренней функции, выполняющей работу. */
 24075	                if (call_nr < 0 || call_nr >= NCALLS) { 
 24076	                        error = ENOSYS;
 24077	                        printf("FS, warning illegal %d system call by %d\n", call_nr, who);
 24078	                } else if (fp->fp_pid == PID_FREE) {
 24079	                        error = ENOSYS;
 24080	                        printf("FS, bad process, who = %d, call_nr = %d, slot1 = %d\n",
 24081	                                 who, call_nr, m_in.slot1);
 24082	                } else {
 24083	                        error = (*call_vec[call_nr])();
 24084	                }
 24085	
 24086	                /* Копирование результатов назад пользователю и передача ответа. */
 24087	                if (error != SUSPEND) { reply(who, error); }
 24088	                if (rdahed_inode != NIL_INODE) {
 24089	                        read_ahead(); /* опережающее чтение блока */
 24090	                }
 24091	        }
 24092	  }
 24093	  return(OK);                           /* мы не должны здесь оказаться */
 24094	}
	
 24096	/*===========================================================================*
 24097	 *                              get_work                                     *
 24098	 *===========================================================================*/
 24099	PRIVATE void get_work()
 24100	{  
 24101	  /* Обычно ожидание нового ввода. Тем не менее, если значение 'reviving' ненулевое,
 24102	   * следует разбудить приостановленный процесс.
 24103	   */
 24104	  register struct fproc *rp;
 24105	
 24106	  if (reviving != 0) {
 24107	        /* Восстановление приостановленного процесса. */
 24108	        for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) 
 24109	                if (rp->fp_revived == REVIVING) {
 24110	                        who = (int)(rp - fproc);
 24111	                        call_nr = rp->fp_fd & BYTE;
 24112	                        m_in.fd = (rp->fp_fd >>8) & BYTE;
 24113	                        m_in.buffer = rp->fp_buffer;
 24114	                        m_in.nbytes = rp->fp_nbytes;
 24115	                        rp->fp_suspended = NOT_SUSPENDED; /* приостановка отменена */
 24116	                        rp->fp_revived = NOT_REVIVING;
 24117	                        reviving--;
 24118	                        return;
 24119	                }
 24120	        panic(__FILE__,"get_work couldn't revive anyone", NO_NUM);
 24121	  }
 24122	
 24123	  /* Обычный случай. Будить никого не надо. */
 24124	  if (receive(ANY, &m_in) != OK) panic(__FILE__,"fs receive error", NO_NUM);
 24125	  who = m_in.m_source;
 24126	  call_nr = m_in.m_type;
 24127	}
	
 24129	/*===========================================================================*
 24130	 *                              buf_pool                                     *
 24131	 *===========================================================================*/
 24132	PRIVATE void buf_pool(void)
 24133	{
 24134	/* Инициализация пула буферов. */
 24135	
 24136	  register struct buf *bp;
 24137	
 24138	  bufs_in_use = 0;
 24139	  front = &buf[0];
 24140	  rear = &buf[NR_BUFS - 1];
 24141	
 24142	  for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) {
 24143	        bp->b_blocknr = NO_BLOCK;
 24144	        bp->b_dev = NO_DEV;
 24145	        bp->b_next = bp + 1;
 24146	        bp->b_prev = bp - 1;
 24147	  }
 24148	  buf[0].b_prev = NIL_BUF;
 24149	  buf[NR_BUFS - 1].b_next = NIL_BUF;
 24150	
 24151	  for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++) bp->b_hash = bp->b_next;
 24152	  buf_hash[0] = front;
 24153	
 24154	}
	
 24156	/*===========================================================================*
 24157	 *                              reply                                        *
 24158	 *===========================================================================*/
 24159	PUBLIC void reply(whom, result)
 24160	int whom;                       /* процесс, которому нужно ответить */
 24161	int result;                     /* результат вызова (обычно OK или номер ошибки) */
 24162	{
 24163	/* Отправка ответа пользовательскому процессу. Отправка может завершиться неудачно
 24164	 * (если процесс был уничтожен сигналом), поэтому код возврата не проверяется. Неудача
 24165	 * при отправке игнорируется.
 24166	 */
 24167	  int s;
 24168	  m_out.reply_type = result;
 24169	  s = send(whom, &m_out);
 24170	  if (s != OK) printf("FS:  couldn't send reply %d:  %d\n", result, s);
 24171	}
	
 24173	/*===========================================================================*
 24174	 *                              fs_init                                      *
 24175	 *===========================================================================*/
 24176	PRIVATE void fs_init()
 24177	{
 24178	/* Инициализация глобальных переменных, таблиц и т. д. */
 24179	  register struct inode *rip;
 24180	  register struct fproc *rfp;
 24181	  message mess;
 24182	  int s;
 24183	
 24184	  /* Инициализация таблицы процессов с помощью сообщений менеджера процессов.
 24185	   * Ожидание для каждого системного процесса одного сообщения с номером записи и pid. 
 24186	   * После инициализации записи последнего процесса посылается магический номер процесса NONE. 
 24187	   * Затем выполняется синхронизация с менеджером процессов.
 24188	   */
 24189	  do {
 24190	        if (OK != (s=receive(PM_PROC_NR, &mess)))
 24191	                panic(__FILE__,"FS couldn't receive from PM", s);
 24192	        if (NONE == mess.PR_PROC_NR) break; 
 24193	
 24194	        rfp = &fproc[mess.PR_PROC_NR];
 24195	        rfp->fp_pid = mess.PR_PID;
 24196	        rfp->fp_realuid = (uid_t) SYS_UID;
 24197	        rfp->fp_effuid = (uid_t) SYS_UID;
 24198	        rfp->fp_realgid = (gid_t) SYS_GID;
 24199	        rfp->fp_effgid = (gid_t) SYS_GID;
 24200	        rfp->fp_umask = ~0;
 24201	   
 24202	  } while (TRUE);                       /* продолжать, пока не получен номер NONE */
 24203	  mess.m_type = OK;                     /* информирование менеджера процессов об успехе */
 24204	  s=send(PM_PROC_NR, &mess);            /* отправка сообщения синхронизации */
 24205	
 24206	  /* Все записи таблицы процессов заданы. Продолжение инициализации файловой системы.
 24207	   * Некоторые связи необходимы для работоспособности файловой системы. Дополнительные
 24208	   * требования к размеру блока проверяются при считывании суперблока.
 24209	   */
 24210	  if (OPEN_MAX > 127) panic(__FILE__,"OPEN_MAX > 127", NO_NUM);
 24211	  if (NR_BUFS < 6) panic(__FILE__,"NR_BUFS < 6", NO_NUM);
 24212	  if (V1_INODE_SIZE != 32) panic(__FILE__,"V1 inode size != 32", NO_NUM);
 24213	  if (V2_INODE_SIZE != 64) panic(__FILE__,"V2 inode size != 64", NO_NUM);
 24214	  if (OPEN_MAX > 8 * sizeof(long))
 24215	         panic(__FILE__,"Too few bits in fp_cloexec", NO_NUM);
 24216	
 24217	  /* Следующие инициализации необходимы для успеха dev_opcl.*/
 24218	  fp = (struct fproc *) NULL;
 24219	  who = FS_PROC_NR;
 24220	
 24221	  buf_pool();                   /* инициализация пула буферов */
 24222	  build_dmap();                 /* создание таблицы устройств и назначение загрузочного драйвера */
 24223	  load_ram();                   /* инициализация виртуального диска и его загрузка, если он корневой */
 24224	  load_super(root_dev);         /* загрузка суперблока корневого устройства */
 24225	  init_select();                /* инициализация структур select() */
 24226	
 24227	  /* Корневое устройство теперь доступно; задание каталогов процессов. */
 24228	  for (rfp=&fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
 24229	        if (rfp->fp_pid != PID_FREE) {
 24230	                rip = get_inode(root_dev, ROOT_INODE);
 24231	                dup_inode(rip);
 24232	                rfp->fp_rootdir = rip;
 24233	                rfp->fp_workdir = rip;
 24234	        }
 24235	  }
 24236	}
	
 24238	/*===========================================================================*
 24239	 *                              igetenv                                      *
 24240	 *===========================================================================*/
 24241	PRIVATE int igetenv(key, optional)
 24242	char *key;
 24243	int optional;
 24244	{
 24245	/* Запрос у ядра целой загрузочной переменной окружения. */
 24246	  char value[64];
 24247	  int i;
 24248	
 24249	  if ((i = env_get_param(key, value, sizeof(value))) != OK) {
 24250	      if (!optional)
 24251	        printf("FS:  Warning, couldn't get monitor param:  %d\n", i);
 24252	      return 0;
 24253	  }
 24254	  return(atoi(value));
 24255	}
	
 24257	/*===========================================================================*
 24258	 *                              load_ram                                     *
 24259	 *===========================================================================*/
 24260	PRIVATE void load_ram(void)
 24261	{
 24262	/* Выделение виртуального диска с размером, заданным в загрузочных параметрах. Если имеется
 24263	 * образ виртуального диска, поблочное копирование образа в виртуальный диск такого же 
 24264	 * размера.
 24265	 * Если корневое устройство не задано, виртуальный диск будет использоваться в его качестве.
 24266	 */
 24267	  register struct buf *bp, *bp1;
 24268	  u32_t lcount, ram_size_kb;
 24269	  zone_t zones;
 24270	  struct super_block *sp, *dsp;
 24271	  block_t b;
 24272	  Dev_t image_dev;
 24273	  static char sbbuf[MIN_BLOCK_SIZE];
 24274	  int block_size_image, block_size_ram, ramfs_block_size;
 24275	  int s;
 24276	
 24277	  /* Получение некоторых переменных окружения. */
 24278	  root_dev = igetenv("rootdev", 0);
 24279	  image_dev = igetenv("ramimagedev", 0);
 24280	  ram_size_kb = igetenv("ramsize", 0);
 24281	
 24282	  /* Открытие корневого устройства. */
 24283	  if (dev_open(root_dev, FS_PROC_NR, R_BIT|W_BIT) != OK)
 24284	        panic(__FILE__,"Cannot open root device",NO_NUM);
 24285	
 24286	  /* Если нам нужно инициализировать виртуальный диск, получение информации из устройства образа. */
 24287	  if (root_dev == DEV_RAM) {
 24288	        u32_t fsmax, probedev;
 24289	
 24290	        /* Если мы запустились с компакт-диска, проверка, можем ли мы найти его. */
 24291	        if (igetenv("cdproberoot", 1) && (probedev=cdprobe()) != NO_DEV) {
 24292	                char devnum[10];
 24293	                struct sysgetenv env;
 24294	
 24295	                /* Если да, это наше новое устройство виртуального диска. */
 24296	                image_dev = probedev;
 24297	
 24298	                /* Информирование о нем менеджера процессов, что позволит пользовательским 
 24299	                 * процессам получить информацию о загрузочном образе с помощью интерфейса sysenv.
 24300	                 */
 24301	                env.key = "cdproberoot";
 24302	                env.keylen = strlen(env.key);
 24303	                sprintf(devnum, "%d", (int) probedev);
 24304	                env.val = devnum;
 24305	                env.vallen = strlen(devnum);
 24306	                svrctl(MMSETPARAM, &env);
 24307	        }
 24308	
 24309	        /* Открытие устройства образа. */
 24310	        if (dev_open(image_dev, FS_PROC_NR, R_BIT) != OK)
 24311	                panic(__FILE__,"Cannot open RAM image device", NO_NUM);
 24312	
 24313	        /* Считывание размера виртуального диска из суперблока. */
 24314	        sp = &super_block[0];
 24315	        sp->s_dev = image_dev;
 24316	        if (read_super(sp) != OK) 
 24317	                panic(__FILE__,"Bad RAM disk image FS", NO_NUM);
 24318	
 24319	        lcount = sp->s_zones << sp->s_log_zone_size;    /* число блоков в корневом устройстве */
 24320	
 24321	        /* Расширение файловой системы виртуального диска до размеров параметров загрузки,
 24322	         * но не дальше, чем позволяет последняя битовая карта зон.
 24323	         */
 24324	        if (ram_size_kb*1024 < lcount*sp->s_block_size)
 24325	                ram_size_kb = lcount*sp->s_block_size/1024;
 24326	        fsmax = (u32_t) sp->s_zmap_blocks * CHAR_BIT * sp->s_block_size;
 24327	        fsmax = (fsmax + (sp->s_firstdatazone-1)) << sp->s_log_zone_size;
 24328	        if (ram_size_kb*1024 > fsmax*sp->s_block_size)
 24329	                ram_size_kb = fsmax*sp->s_block_size/1024;
 24330	  }
 24331	
 24332	  /* Указание драйверу виртуального диска размера виртуального диска. */
 24333	  m_out.m_type = DEV_IOCTL;
 24334	  m_out.PROC_NR = FS_PROC_NR;
 24335	  m_out.DEVICE = RAM_DEV;
 24336	  m_out.REQUEST = MIOCRAMSIZE;                  /* управление вводом-выводом */
 24337	  m_out.POSITION = (ram_size_kb * 1024);        /* запрос в байтах */
 24338	  if ((s=sendrec(MEM_PROC_NR, &m_out)) != OK)
 24339	        panic("FS","sendrec from MEM failed", s);
 24340	  else if (m_out.REP_STATUS != OK) {
 24341	 /* Информировать и продолжать, если виртуальный диск не затребован в качестве корневой файловой системы. */
 24342	        if (root_dev != DEV_RAM) {
 24343	                report("FS","can't set RAM disk size", m_out.REP_STATUS);
 24344	                return;
 24345	        } else {
 24346	                panic(__FILE__,"can't set RAM disk size", m_out.REP_STATUS);
 24347	        }
 24348	  }
 24349	
 24350	  /* Проверка, должны ли мы загружать образ виртуального диска, иначе возврат. */
 24351	  if (root_dev != DEV_RAM)
 24352	        return;
 24353	
 24354	  /* Поблочное копирование образа в виртуальный диск. */
 24355	  printf("Loading RAM disk onto /dev/ram: \33[23CLoaded:     0 KB");
 24356	
 24357	  inode[0].i_mode = I_BLOCK_SPECIAL;    /* временный индексный узел для rahead() */
 24358	  inode[0].i_size = LONG_MAX;
 24359	  inode[0].i_dev = image_dev;
 24360	  inode[0].i_zone[0] = image_dev;
 24361	
 24362	  block_size_ram = get_block_size(DEV_RAM);
 24363	  block_size_image = get_block_size(image_dev);
 24364	
 24365	  /* Размер блока виртуального диска должен быть кратен размеру блока корневого устройства
 24366	   * для упрощения копирования.
 24367	   */
 24368	  if (block_size_image % block_size_ram) {
 24369	        printf("\nram block size:  %d image block size:  %d\n", 
 24370	                block_size_ram, block_size_image);
 24371	        panic(__FILE__, "ram disk block size must be a multiple of "
 24372	                "the image disk block size", NO_NUM);
 24373	  }
 24374	
 24375	  /* Загрузка блоков из устройства образа. */
 24376	  for (b = 0; b < (block_t) lcount; b++) {
 24377	        int rb, factor;
 24378	        bp = rahead(&inode[0], b, (off_t)block_size_image * b, block_size_image);
 24379	        factor = block_size_image/block_size_ram;
 24380	        for(rb = 0; rb < factor; rb++) {
 24381	                bp1 = get_block(root_dev, b * factor + rb, NO_READ);
 24382	                memcpy(bp1->b_data, bp->b_data + rb * block_size_ram,
 24383	                        (size_t) block_size_ram);
 24384	                bp1->b_dirt = DIRTY;
 24385	                put_block(bp1, FULL_DATA_BLOCK);
 24386	        }
 24387	        put_block(bp, FULL_DATA_BLOCK);
 24388	        if (b % 11 == 0)
 24389	        printf("\b\b\b\b\b\b\b\b\b%6ld KB", ((long) b * block_size_image)/1024L);
 24390	  }
 24391	
 24392	  /* Передача изменений в память, чтобы они стали видимы dev_io. */
 24393	  do_sync();
 24394	
 24395	  printf("\rRAM disk of %u KB loaded onto /dev/ram.", (unsigned) ram_size_kb);
 24396	  if (root_dev == DEV_RAM) printf(" Using RAM disk as root FS.");
 24397	  printf("  \n");
 24398	
 24399	  /* Объявление недействительным и закрытие устройства образа. */
 24400	  invalidate(image_dev);
 24401	  dev_close(image_dev);
 24402	
 24403	  /* Изменение размера корневой файловой системы виртуального диска. */
 24404	  if (dev_io(DEV_READ, root_dev, FS_PROC_NR,
 24405	        sbbuf, SUPER_BLOCK_BYTES, MIN_BLOCK_SIZE, 0) != MIN_BLOCK_SIZE) {
 24406	        printf("WARNING:  ramdisk read for resizing failed\n");
 24407	  }
 24408	  dsp = (struct super_block *) sbbuf;
 24409	  if (dsp->s_magic == SUPER_V3)
 24410	        ramfs_block_size = dsp->s_block_size;
 24411	  else
 24412	        ramfs_block_size = STATIC_BLOCK_SIZE;
 24413	  zones = (ram_size_kb * 1024 / ramfs_block_size) >> sp->s_log_zone_size;
 24414	
 24415	  dsp->s_nzones = conv2(sp->s_native, (u16_t) zones);
 24416	  dsp->s_zones = conv4(sp->s_native, zones);
 24417	  if (dev_io(DEV_WRITE, root_dev, FS_PROC_NR,
 24418	        sbbuf, SUPER_BLOCK_BYTES, MIN_BLOCK_SIZE, 0) != MIN_BLOCK_SIZE) {
 24419	        printf("WARNING:  ramdisk write for resizing failed\n");
 24420	  }
 24421	}
	
 24423	/*===========================================================================*
 24424	 *                              load_super                                   *
 24425	 *===========================================================================*/
 24426	PRIVATE void load_super(super_dev)
 24427	dev_t super_dev;                        /* место считывания суперблока  */
 24428	{
 24429	  int bad;
 24430	  register struct super_block *sp;
 24431	  register struct inode *rip;
 24432	
 24433	  /* Инициализация таблицы суперблоков. */
 24434	  for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++)
 24435	        sp->s_dev = NO_DEV;
 24436	
 24437	  /* Чтение суперблока корневой файловой системы. */
 24438	  sp = &super_block[0];
 24439	  sp->s_dev = super_dev;
 24440	
 24441	  /* Проверка корректности суперблока. */
 24442	  bad = (read_super(sp) != OK);
 24443	  if (!bad) {
 24444	        rip = get_inode(super_dev, ROOT_INODE); /* индексный узел корневого каталога */
 24445	        if ( (rip->i_mode & I_TYPE) != I_DIRECTORY || rip->i_nlinks < 3) bad++;
 24446	  }
 24447	  if (bad) panic(__FILE__,"Invalid root file system", NO_NUM);
 24448	
 24449	  sp->s_imount = rip;
 24450	  dup_inode(rip);
 24451	  sp->s_isup = rip;
 24452	  sp->s_rd_only = 0;
 24453	  return;
 24454	}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/open.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 24500	/* Этот файл содержит процедуры создания, открытия, закрытия и поиска
 24501	 * в файлах.
 24502	 *
 24503	 * Файл имеет следующие точки входа:
 24504	 *   do_creat:   выполнение системного вызова CREAT
 24505	 *   do_open:    выполнение системного вызова OPEN
 24506	 *   do_mknod:   выполнение системного вызова MKNOD
 24507	 *   do_mkdir:   выполнение системного вызова MKDIR
 24508	 *   do_close:   выполнение системного вызова CLOSE
 24509	 *   do_lseek:   выполнение системного вызова LSEEK
 24510	 */
 24511	
 24512	#include "fs.h"
 24513	#include <sys/stat.h>
 24514	#include <fcntl.h>
 24515	#include <minix/callnr.h>
 24516	#include <minix/com.h>
 24517	#include "buf.h"
 24518	#include "file.h"
 24519	#include "fproc.h"
 24520	#include "inode.h"
 24521	#include "lock.h"
 24522	#include "param.h"
 24523	#include "super.h"
 24524	
 24525	#define offset m2_l1
 24526	
 24527	PRIVATE char mode_map[] = {R_BIT, W_BIT, R_BIT|W_BIT, 0};
 24528	
 24529	FORWARD _PROTOTYPE( int common_open, (int oflags, mode_t omode)         );
 24530	FORWARD _PROTOTYPE( int pipe_open, (struct inode *rip,mode_t bits,int oflags));
 24531	FORWARD _PROTOTYPE( struct inode *new_node, (char *path, mode_t bits,
 24532	                                                        zone_t z0)      );
 24533	
 24534	/*===========================================================================*
 24535	 *                              do_creat                                     *
 24536	 *===========================================================================*/
 24537	PUBLIC int do_creat()
 24538	{
 24539	/* Выполнение системного вызова creat(name, mode). */
 24540	  int r;
 24541	
 24542	  if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
 24543	  r = common_open(O_WRONLY | O_CREAT | O_TRUNC, (mode_t) m_in.mode);
 24544	  return(r);
 24545	}
	
 24547	/*===========================================================================*
 24548	 *                              do_open                                      *
 24549	 *===========================================================================*/
 24550	PUBLIC int do_open()
 24551	{
 24552	/* Выполнение системного вызова open(name, flags,...). */
 24553	
 24554	  int create_mode = 0;          /* на самом деле тип mode_t, но это вызывает проблемы */
 24555	  int r;
 24556	
 24557	  /* Если значение O_CREAT установлено, open имеет три параметра, иначе два. */
 24558	  if (m_in.mode & O_CREAT) {
 24559	        create_mode = m_in.c_mode;      
 24560	        r = fetch_name(m_in.c_name, m_in.name1_length, M1);
 24561	  } else {
 24562	        r = fetch_name(m_in.name, m_in.name_length, M3);
 24563	  }
 24564	
 24565	  if (r != OK) return(err_code); /* некорректное имя */
 24566	  r = common_open(m_in.mode, create_mode);
 24567	  return(r);
 24568	}
	
 24570	/*===========================================================================*
 24571	 *                              common_open                                  *
 24572	 *===========================================================================*/
 24573	PRIVATE int common_open(register int oflags, mode_t omode)
 24574	{
 24575	/* Общий код do_creat и do_open. */
 24576	
 24577	  register struct inode *rip;
 24578	  int r, b, exist = TRUE;
 24579	  dev_t dev;
 24580	  mode_t bits;
 24581	  off_t pos;
 24582	  struct filp *fil_ptr, *filp2;
 24583	
 24584	  /* Повторное создание карты двух младших битов oflags. */
 24585	  bits = (mode_t) mode_map[oflags & O_ACCMODE];
 24586	
 24587	  /* Проверка доступности дескриптора файла и записей filp. */
 24588	  if ( (r = get_fd(0, bits, &m_in.fd, &fil_ptr)) != OK) return(r);
 24589	
 24590	  /* Если значение O_CREATE установлено, попытка создать файл. */ 
 24591	  if (oflags & O_CREAT) {
 24592	        /* Создание нового индексного узла вызовом new_node(). */
 24593	        omode = I_REGULAR | (omode & ALL_MODES & fp->fp_umask);
 24594	        rip = new_node(user_path, omode, NO_ZONE);
 24595	        r = err_code;
 24596	        if (r == OK) exist = FALSE;      /* мы просто создали файл */
 24597	        else if (r != EEXIST) return(r); /* другая ошибка */
 24598	        else exist = !(oflags & O_EXCL); /* файл существует, если флаг O_EXCL 
 24599	                                            установлен, это ошибка */
 24600	  } else {
 24601	         /* Сканирование пути. */
 24602	        if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
 24603	  }
 24604	
 24605	  /* Claim дескриптора файла и записи filp, их заполнение. */
 24606	  fp->fp_filp[m_in.fd] = fil_ptr;
 24607	  fil_ptr->filp_count = 1;
 24608	  fil_ptr->filp_ino = rip;
 24609	  fil_ptr->filp_flags = oflags;
 24610	
 24611	  /* Выполнение обычного кода открытия файла, только если мы не создали файл. */
 24612	  if (exist) {
 24613	        /* Проверка защиты. */
 24614	        if ((r = forbidden(rip, bits)) == OK) {
 24615	                /* Открытие обычных файлов, каталогов и специальных файлов различается. */
 24616	                switch (rip->i_mode & I_TYPE) {
 24617	                   case I_REGULAR:  
 24618	                        /* Отбрасывание обычного файла, если установлено значение O_TRUNC. */
 24619	                        if (oflags & O_TRUNC) {
 24620	                                if ((r = forbidden(rip, W_BIT)) !=OK) break;
 24621	                                truncate(rip);
 24622	                                wipe_inode(rip);
 24623	                                /* Скопировать индексный узел из кэша индексных узлов в кэш
 24624	                                 * блоков, чтобы он был записан при следующем сбросе
 24625	                                 * кэша.
 24626	                                 */
 24627	                                rw_inode(rip, WRITING);
 24628	                        }
 24629	                        break;
 24630	 
 24631	                   case I_DIRECTORY:  
 24632	                        /* Каталоги можно читать, но в них нельзя писать. */
 24633	                        r = (bits & W_BIT ? EISDIR :  OK);
 24634	                        break;
 24635	
 24636	                   case I_CHAR_SPECIAL: 
 24637	                   case I_BLOCK_SPECIAL: 
 24638	                        /* Вызов драйвера для специальной обработки. */
 24639	                        dev = (dev_t) rip->i_zone[0];
 24640	                        r = dev_open(dev, who, bits | (oflags & ~O_ACCMODE));
 24641	                        break;
 24642	
 24643	                   case I_NAMED_PIPE: 
 24644	                        oflags |= O_APPEND;     /* принудительный режим добавления */
 24645	                        fil_ptr->filp_flags = oflags;
 24646	                        r = pipe_open(rip, bits, oflags);
 24647	                        if (r != ENXIO) {
 24648	                                /* Проверка, ведет ли какой-либо процесс чтение или запись
 24649	                                 * в FIFO.  Если да, использование записи filp этого процесса
 24650	                                 * для автоматического совместного использования позиции файла.
 24651	                                 */
 24652	                                b = (bits & R_BIT ? R_BIT :  W_BIT);
 24653	                                fil_ptr->filp_count = 0; /* don't find self */
 24654	                                if ((filp2 = find_filp(rip, b)) != NIL_FILP) {
 24655	                                        /* Компаньон по чтению/записи найден. Воспользоваться этим.*/
 24656	                                        fp->fp_filp[m_in.fd] = filp2;
 24657	                                        filp2->filp_count++;
 24658	                                        filp2->filp_ino = rip;
 24659	                                        filp2->filp_flags = oflags;
 24660	
 24661	                                        /* величина i_count была некорректно инкрементирована
 24662	                                         * ранее - не было известно, что мы собираемся
 24663	                                         * использовать существующую запись filp.
 24664	                                         * Исправление ошибки.
 24665	                                         */
 24666	                                        rip->i_count--;
 24667	                                } else {
 24668	                                        /* Никто больше не найден. Восстановление filp. */
 24669	                                        fil_ptr->filp_count = 1;
 24670	                                        if (b == R_BIT)
 24671	                                             pos = rip->i_zone[V2_NR_DZONES+0];
 24672	                                        else
 24673	                                             pos = rip->i_zone[V2_NR_DZONES+1];
 24674	                                        fil_ptr->filp_pos = pos;
 24675	                                }
 24676	                        }
 24677	                        break;
 24678	                }
 24679	        }
 24680	  }
 24681	
 24682	  /* В случае ошибки освободить индексный узел. */
 24683	  if (r != OK) {
 24684	        if (r == SUSPEND) return(r);            /* Процесс только что был приостановлен */
 24685	        fp->fp_filp[m_in.fd] = NIL_FILP;
 24686	        fil_ptr->filp_count= 0;
 24687	        put_inode(rip);
 24688	        return(r);
 24689	  }
 24690	  
 24691	  return(m_in.fd);
 24692	}
	
 24694	/*===========================================================================*
 24695	 *                              new_node                                     *
 24696	 *===========================================================================*/
 24697	PRIVATE struct inode *new_node(char *path, mode_t bits, zone_t z0)
 24698	{
 24699	/* Функция new_node() вызывается функциями common_open(), do_mknod() и do_mkdir().  
 24700	 * Во всех случаях она выделяет новый индексный узел, создает для него запись в каталоге, 
 24701	 * заданном переменной 'path', и инициализирует ее. Указатель на индексный узел возвращается,
 24702	 * если это возможно; в противном случае возвращается NIL_INODE. Функция всегда устанавливает
 24703	 * переменную 'err_code' в надлежащее значение (OK или код ошибки).
 24704	 */
 24705	
 24706	  register struct inode *rlast_dir_ptr, *rip;
 24707	  register int r;
 24708	  char string[NAME_MAX];
 24709	
 24710	  /* Открываются ли все каталоги, указанные в пути? */
 24711	  if ((rlast_dir_ptr = last_dir(path, string)) == NIL_INODE) return(NIL_INODE);
 24712	
 24713	  /* Последний каталог доступен. Получение последнего компонента пути. */
 24714	  rip = advance(rlast_dir_ptr, string);
 24715	  if ( rip == NIL_INODE && err_code == ENOENT) {
 24716	        /* Последний компонент пути не существует. Создание новой записи каталога. */
 24717	        if ( (rip = alloc_inode(rlast_dir_ptr->i_dev, bits)) == NIL_INODE) {
 24718	                /* Невозможно создать новый индексный узел. */
 24719	                put_inode(rlast_dir_ptr);
 24720	                return(NIL_INODE);
 24721	        }
 24722	
 24723	        /* Сброс индексного узла на диск до создания записи в каталоге, чтобы сделать систему
 24724	         * более приспособленной к восстановлению в случае аварии: индексный узел
 24725	         * без записи каталога лучше, чем наоборот.
 24726	         */
 24727	        rip->i_nlinks++;
 24728	        rip->i_zone[0] = z0;            /* главный/вспомогательный номер устройства */
 24729	        rw_inode(rip, WRITING);         /* сброс индексного узла на диск */
 24730	
 24731	        /* Создан новый индексный узел. Попытка создать запись каталога. */
 24732	        if ((r = search_dir(rlast_dir_ptr, string, &rip->i_num,ENTER)) != OK) {
 24733	                put_inode(rlast_dir_ptr);
 24734	                rip->i_nlinks--;        /* увы, необходимо освободить индексный узел на диске */
 24735	                rip->i_dirt = DIRTY;    /* сброс измененных индексных узлов */
 24736	                put_inode(rip);         /* вызов, освобождающий индексный узел */
 24737	                err_code = r;
 24738	                return(NIL_INODE);
 24739	        }
 24740	
 24741	  } else {
 24742	        /*  Последний компонент существует, либо возникла какая-то проблема. */
 24743	        if (rip != NIL_INODE)
 24744	                r = EEXIST;
 24745	        else
 24746	                r = err_code;
 24747	  }
 24748	
 24749	  /* Возврат индексного узла каталога и выход. */
 24750	  put_inode(rlast_dir_ptr);
 24751	  err_code = r;
 24752	  return(rip);
 24753	}
	
 24755	/*===========================================================================*
 24756	 *                              pipe_open                                    *
 24757	 *===========================================================================*/
 24758	PRIVATE int pipe_open(register struct inode *rip, register mode_t bits,
 24759	        register int oflags)
 24760	{
 24761	/*  Эта функция вызывается common_open. Она проверяет наличие хотя бы одной пары
 24762	 *  процессов, читающих из канала и пишущих в канал. Если такой пары нет, функция 
 24763	 *  приостанавливает процесс, совершивший вызов, в противном случае восстанавливает
 24764	 *  все процессы, блокированные каналом.
 24765	 */
 24766	
 24767	  rip->i_pipe = I_PIPE; 
 24768	  if (find_filp(rip, bits & W_BIT ? R_BIT :  W_BIT) == NIL_FILP) { 
 24769	        if (oflags & O_NONBLOCK) {
 24770	                if (bits & W_BIT) return(ENXIO);
 24771	        } else {
 24772	                suspend(XPOPEN);        /* приостановка совершившего вызов процесса */
 24773	                return(SUSPEND);
 24774	        }
 24775	  } else if (susp_count > 0) {/* снятие блокировки с процессов */
 24776	        release(rip, OPEN, susp_count);
 24777	        release(rip, CREAT, susp_count);
 24778	  }
 24779	  return(OK);
 24780	}
	
 24782	/*===========================================================================*
 24783	 *                              do_mknod                                     *
 24784	 *===========================================================================*/
 24785	PUBLIC int do_mknod()
 24786	{
 24787	/* Выполнение системного вызова mknod(name, mode, addr). */
 24788	
 24789	  register mode_t bits, mode_bits;
 24790	  struct inode *ip;
 24791	
 24792	  /* Создавать не FIFO-узлы может только суперпользователь. */
 24793	  mode_bits = (mode_t) m_in.mk_mode;            /* режим индексного узла */
 24794	  if (!super_user && ((mode_bits & I_TYPE) != I_NAMED_PIPE)) return(EPERM);
 24795	  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
 24796	  bits = (mode_bits & I_TYPE) | (mode_bits & ALL_MODES & fp->fp_umask);
 24797	  ip = new_node(user_path, bits, (zone_t) m_in.mk_z0);
 24798	  put_inode(ip);
 24799	  return(err_code);
 24800	}
	
 24802	/*===========================================================================*
 24803	 *                              do_mkdir                                     *
 24804	 *===========================================================================*/
 24805	PUBLIC int do_mkdir()
 24806	{
 24807	/* Выполнение системного вызова mkdir(name, mode). */
 24808	
 24809	  int r1, r2;                   /* коды состояния */
 24810	  ino_t dot, dotdot;            /* номера индексных узлов для каталогов . и .. */
 24811	  mode_t bits;                  /* биты режима для нового индексного узла */
 24812	  char string[NAME_MAX];        /* последний компонент пути нового каталога */
 24813	  register struct inode *rip, *ldirp;
 24814	
 24815	  /* Проверка возможности создания еще одной связи в родительском каталоге. */
 24816	  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
 24817	  ldirp = last_dir(user_path, string);  /* указатель на родительский каталог нового каталога */
 24818	  if (ldirp == NIL_INODE) return(err_code);
 24819	  if (ldirp->i_nlinks >= (ldirp->i_sp->s_version == V1 ?
 24820	         CHAR_MAX :  SHRT_MAX)) {
 24821	        put_inode(ldirp);       /* возврат родительского каталога */
 24822	        return(EMLINK);
 24823	  }
 24824	
 24825	  /* Создание индексного узла. Если не получается, возврат кода ошибки. */
 24826	  bits = I_DIRECTORY | (m_in.mode & RWX_MODES & fp->fp_umask);
 24827	  rip = new_node(user_path, bits, (zone_t) 0);
 24828	  if (rip == NIL_INODE || err_code == EEXIST) {
 24829	        put_inode(rip);         /* невозможно создать каталог: он уже существует */
 24830	        put_inode(ldirp);       /* возврат родительского каталога */
 24831	        return(err_code);
 24832	  }
 24833	
 24834	  /* Получение номеров индексных узлов для каталогов . и .. для ввода в каталог. */
 24835	  dotdot = ldirp->i_num;        /* номер индексного узла родительского каталога */
 24836	  dot = rip->i_num;             /* номер индексного узла нового каталога */
 24837	
 24838	  /* Создание записей для каталогов . и .., если диск не заполнен целиком. */
 24839	  /* Использование dot1 и dot2, чтобы режим каталога был не важен. */
 24840	  rip->i_mode = bits;   /* задание режима */
 24841	  r1 = search_dir(rip, dot1, &dot, ENTER);      /* ввод . в новый каталог */
 24842	  r2 = search_dir(rip, dot2, &dotdot, ENTER);   /* ввод .. в новый каталог */
 24843	
 24844	  /* Если добавление каталогов . и .. было успешным, увеличить счетчики связей. */
 24845	  if (r1 == OK && r2 == OK) {
 24846	        /* Обычный случай. Добавление каталогов . и .. было успешным. */
 24847	        rip->i_nlinks++;        /* учет . */
 24848	        ldirp->i_nlinks++;      /* учет  .. */
 24849	        ldirp->i_dirt = DIRTY;  /* пометка индексного узла родительского каталога как измененного */
 24850	  } else {
 24851	        /* Не удалось добавить как минимум один из каталогов . и .., возможно, диск полон. */
 24852	        (void) search_dir(ldirp, string, (ino_t *) 0, DELETE);
 24853	        rip->i_nlinks--;        /* отмена инкрементирования, выполненного в new_node() */
 24854	  }
 24855	  rip->i_dirt = DIRTY;          /* в любом случае значение i_nlinks изменилось */
 24856	
 24857	  put_inode(ldirp);             /* возврат индексного узла родительского каталога */
 24858	  put_inode(rip);               /* возврат индексного узла нового каталога */
 24859	  return(err_code);             /* new_node() всегда устанавливает значение 'err_code' */
 24860	}
	
 24862	/*===========================================================================*
 24863	 *                              do_close                                     *
 24864	 *===========================================================================*/
 24865	PUBLIC int do_close()
 24866	{
 24867	/* выполнение системного вызова close(fd). */
 24868	
 24869	  register struct filp *rfilp;
 24870	  register struct inode *rip;
 24871	  struct file_lock *flp;
 24872	  int rw, mode_word, lock_count;
 24873	  dev_t dev;
 24874	
 24875	  /* Сначала обнаружение индексного узла, принадлежащего дескриптору файла. */
 24876	  if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
 24877	  rip = rfilp->filp_ino;        /* 'rip' указывает на индексный узел */
 24878	
 24879	  if (rfilp->filp_count - 1 == 0 && rfilp->filp_mode != FILP_CLOSED) {
 24880	        /* Проверка, является ли файл специальным. */
 24881	        mode_word = rip->i_mode & I_TYPE;
 24882	        if (mode_word == I_CHAR_SPECIAL || mode_word == I_BLOCK_SPECIAL) {
 24883	                dev = (dev_t) rip->i_zone[0];
 24884	                if (mode_word == I_BLOCK_SPECIAL)  {
 24885	                        /* Объявление записей кэша недействительными, если не специальный 
 24886	                         * файл или ROOT
 24887	                         */
 24888	                        if (!mounted(rip)) {
 24889	                                (void) do_sync();       /* очистка кэша */
 24890	                                invalidate(dev);
 24891	                        }    
 24892	                }
 24893	                /* Специальная обработка при закрытии устройства. */
 24894	                dev_close(dev);
 24895	        }
 24896	  }
 24897	
 24898	  /* Если закрываемый индексный узел является каналом, освобождение всех, кто блокирован этим каналом. */
 24899	  if (rip->i_pipe == I_PIPE) {
 24900	        rw = (rfilp->filp_mode & R_BIT ? WRITE :  READ);
 24901	        release(rip, rw, NR_PROCS);
 24902	  }
 24903	
 24904	  /* Если запись выполнена, индексный узел уже помечен как измененный . */
 24905	  if (--rfilp->filp_count == 0) {
 24906	        if (rip->i_pipe == I_PIPE && rip->i_count > 1) {
 24907	                /* Сохранение позиции файла в индексном узле на случай применения в будущем.
 24908	                 * Позиции чтения и записи сохраняются по отдельности. Последние 3 зоны
 24909	                 * индексного узла не используются для именованных каналов.
 24910	                 */
 24911	                if (rfilp->filp_mode == R_BIT)
 24912	                        rip->i_zone[V2_NR_DZONES+0] = (zone_t) rfilp->filp_pos;
 24913	                else
 24914	                        rip->i_zone[V2_NR_DZONES+1] = (zone_t) rfilp->filp_pos;
 24915	        }
 24916	        put_inode(rip);
 24917	  }
 24918	
 24919	  fp->fp_cloexec &= ~(1L << m_in.fd);   /* отключение бита закрытия при вызове exec */
 24920	  fp->fp_filp[m_in.fd] = NIL_FILP;
 24921	
 24922	  /* Проверка блокирования файла. Если блокировки есть, их снятие. */
 24923	  if (nr_locks == 0) return(OK);
 24924	  lock_count = nr_locks;        /* сохранение числа блокировок */
 24925	  for (flp = &file_lock[0]; flp < &file_lock[NR_LOCKS]; flp++) {
 24926	        if (flp->lock_type == 0) continue;      /* запись не используется */
 24927	        if (flp->lock_inode == rip && flp->lock_pid == fp->fp_pid) {
 24928	                flp->lock_type = 0;
 24929	                nr_locks--;
 24930	        }
 24931	  }
 24932	  if (nr_locks < lock_count) lock_revive();     /* блокировка снята */
 24933	  return(OK);
 24934	}
	
 24936	/*===========================================================================*
 24937	 *                              do_lseek                                     *
 24938	 *===========================================================================*/
 24939	PUBLIC int do_lseek()
 24940	{
 24941	/* выполнение системного вызова lseek(ls_fd, offset, whence). */
 24942	
 24943	  register struct filp *rfilp;
 24944	  register off_t pos;
 24945	
 24946	  /* Проверка допустимости дескриптора файла. */
 24947	  if ( (rfilp = get_filp(m_in.ls_fd)) == NIL_FILP) return(err_code);
 24948	
 24949	  /* lseek не выполняется для каналов. */
 24950	  if (rfilp->filp_ino->i_pipe == I_PIPE) return(ESPIPE);
 24951	
 24952	  /* Значение 'whence' определяет начальную используемую позицию. */
 24953	  switch(m_in.whence) {
 24954	        case 0:  pos = 0;        break;
 24955	        case 1:  pos = rfilp->filp_pos;  break;
 24956	        case 2:  pos = rfilp->filp_ino->i_size;  break;
 24957	        default:  return(EINVAL);
 24958	  }
 24959	
 24960	  /* Проверка переполнения. */
 24961	  if (((long)m_in.offset > 0) && ((long)(pos + m_in.offset) < (long)pos)) 
 24962	        return(EINVAL);
 24963	  if (((long)m_in.offset < 0) && ((long)(pos + m_in.offset) > (long)pos)) 
 24964	        return(EINVAL);
 24965	  pos = pos + m_in.offset;
 24966	
 24967	  if (pos != rfilp->filp_pos)
 24968	        rfilp->filp_ino->i_seek = ISEEK;        /* подавление опережающего чтения */
 24969	  rfilp->filp_pos = pos;
 24970	  m_out.reply_l1 = pos;         /* вставка long в выходное сообщение */
 24971	  return(OK);
 24972	}





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/read.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 25000	/* Этот файл содержит ядро механизма чтения и записи файлов. Запросы на чтение
 25001	 * и запись разбиваются на фрагменты, не пересекающие границ блоков. Все фрагменты
 25002	 * обрабатываются по очереди. Чтение специальных файлов также обнаруживается и  
 25003	 * выполняется.
 25004	 *
 25005	 * Файл имеет следующие точки входа
 25006	 *   do_read:     выполнение системного вызова READ путем вызова read_write
 25007	 *   read_write:  фактическое выполнение работы READ и WRITE
 25008	 *   read_map:    поиск номера зоны по индексному узлу и позиции в файле
 25009	 *   rd_indir:    чтение записи в косвенном блоке
 25010	 *   read_ahead:  управление опережающим чтением блоков
 25011	 */
 25012	
 25013	#include "fs.h"
 25014	#include <fcntl.h>
 25015	#include <minix/com.h>
 25016	#include "buf.h"
 25017	#include "file.h"
 25018	#include "fproc.h"
 25019	#include "inode.h"
 25020	#include "param.h"
 25021	#include "super.h"
 25022	
 25023	FORWARD _PROTOTYPE( int rw_chunk, (struct inode *rip, off_t position,
 25024	        unsigned off, int chunk, unsigned left, int rw_flag,
 25025	        char *buff, int seg, int usr, int block_size, int *completed));
 25026	
 25027	/*===========================================================================*
 25028	 *                              do_read                                      *
 25029	 *===========================================================================*/
 25030	PUBLIC int do_read()
 25031	{
 25032	  return(read_write(READING));
 25033	}
	
 25035	/*===========================================================================*
 25036	 *                              read_write                                   *
 25037	 *===========================================================================*/
 25038	PUBLIC int read_write(rw_flag)
 25039	int rw_flag;                    /* чтение или запись */
 25040	{
 25041	/* выполнение системных вызовов read(fd, buffer, nbytes) и write(fd, buffer, nbytes). */
 25042	
 25043	  register struct inode *rip;
 25044	  register struct filp *f;
 25045	  off_t bytes_left, f_size, position;
 25046	  unsigned int off, cum_io;
 25047	  int op, oflags, r, chunk, usr, seg, block_spec, char_spec;
 25048	  int regular, partial_pipe = 0, partial_cnt = 0;
 25049	  mode_t mode_word;
 25050	  struct filp *wf;
 25051	  int block_size;
 25052	  int completed, r2 = OK;
 25053	  phys_bytes p;
 25054	
 25055	  /* Остались незавершенные вызовы rw_chunk() из предыдущего вызова! Это невозможно и означает,
 25056	   * что мы не можем исправить эту ошибку.
 25057	   */
 25058	  if (bufs_in_use < 0) {
 25059	        panic(__FILE__,"start - bufs_in_use negative", bufs_in_use);
 25060	  }
 25061	
 25062	  /* Менеджер процессов загружает сегменты, записывая забавные вещи в старшие 10 бит 'fd'. */
 25063	  if (who == PM_PROC_NR && (m_in.fd & (~BYTE)) ) {
 25064	        usr = m_in.fd >> 7;
 25065	        seg = (m_in.fd >> 5) & 03;
 25066	        m_in.fd &= 037;         /* избавляемся от битов пользователя и сегмента */
 25067	  } else {
 25068	        usr = who;              /* обычный случай */
 25069	        seg = D;
 25070	  }
 25071	
 25072	  /* Если дескриптор файла допустим, получение индексного узла, размера и режима. */
 25073	  if (m_in.nbytes < 0) return(EINVAL);
 25074	  if ((f = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
 25075	  if (((f->filp_mode) & (rw_flag == READING ? R_BIT :  W_BIT)) == 0) {
 25076	        return(f->filp_mode == FILP_CLOSED ? EIO :  EBADF);
 25077	  }
 25078	  if (m_in.nbytes == 0)
 25079	         return(0);     /* символьные специальные файлы не нужно проверять на 0*/
 25080	
 25081	  /* Проверка наличия у пользовательского процесса необходимой памяти.
 25082	   * Если необходимой памяти нет, копирование завершится неудачей.
 25083	   * Предварительная проверка на 0 обусловлена тем, что umap не нужны нулевые байты.
 25084	   */
 25085	  if ((r = sys_umap(usr, seg, (vir_bytes) m_in.buffer, m_in.nbytes, &p)) != OK)
 25086	        return r;
 25087	  position = f->filp_pos;
 25088	  oflags = f->filp_flags;
 25089	  rip = f->filp_ino;
 25090	  f_size = rip->i_size;
 25091	  r = OK;
 25092	  if (rip->i_pipe == I_PIPE) {
 25093	        /* fp->fp_cum_io_partial не равно нулю только при частичной записи */
 25094	        cum_io = fp->fp_cum_io_partial; 
 25095	  } else {
 25096	        cum_io = 0;
 25097	  }
 25098	  op = (rw_flag == READING ? DEV_READ :  DEV_WRITE);
 25099	  mode_word = rip->i_mode & I_TYPE;
 25100	  regular = mode_word == I_REGULAR || mode_word == I_NAMED_PIPE;
 25101	
 25102	  if ((char_spec = (mode_word == I_CHAR_SPECIAL ? 1 :  0))) {
 25103	        if (rip->i_zone[0] == NO_DEV)
 25104	                panic(__FILE__,"read_write tries to read from "
 25105	                        "character device NO_DEV", NO_NUM);
 25106	        block_size = get_block_size(rip->i_zone[0]);
 25107	  }
 25108	  if ((block_spec = (mode_word == I_BLOCK_SPECIAL ? 1 :  0))) {
 25109	        f_size = ULONG_MAX;
 25110	        if (rip->i_zone[0] == NO_DEV)
 25111	                panic(__FILE__,"read_write tries to read from "
 25112	                " block device NO_DEV", NO_NUM);
 25113	        block_size = get_block_size(rip->i_zone[0]);
 25114	  }
 25115	
 25116	  if (!char_spec && !block_spec)
 25117	        block_size = rip->i_sp->s_block_size;
 25118	
 25119	  rdwt_err = OK;                /* устанавливается в EIO при ошибках диска */
 25120	
 25121	  /* Проверка символьных специальных файлов. */
 25122	  if (char_spec) {
 25123	        dev_t dev;
 25124	        dev = (dev_t) rip->i_zone[0];
 25125	        r = dev_io(op, dev, usr, m_in.buffer, position, m_in.nbytes, oflags);
 25126	        if (r >= 0) {
 25127	                cum_io = r;
 25128	                position += r;
 25129	                r = OK;
 25130	        }
 25131	  } else {
 25132	        if (rw_flag == WRITING && block_spec == 0) {
 25133	                /* Предварительная проверка слишком большого размера файла. */
 25134	                if (position > rip->i_sp->s_max_size - m_in.nbytes) 
 25135	                        return(EFBIG);
 25136	
 25137	                /* Проверка флага O_APPEND. */
 25138	                if (oflags & O_APPEND) position = f_size;
 25139	
 25140	                /* Очистка зоны, содержащей текущий конец файла, если будет создана
 25141	                 * дыра. Это необходимо, поскольку все незаписанные блоки перед концом
 25142	                 * файла должны считываться как нулевые.
 25143	                 */
 25144	                if (position > f_size) clear_zone(rip, f_size, 0);
 25145	        }
 25146	
 25147	        /* С каналами все немного иначе. Проверка. */
 25148	        if (rip->i_pipe == I_PIPE) {
 25149	               r = pipe_check(rip, rw_flag, oflags,
 25150	                        m_in.nbytes, position, &partial_cnt, 0);
 25151	               if (r <= 0) return(r);
 25152	        }
 25153	
 25154	        if (partial_cnt > 0) partial_pipe = 1;
 25155	
 25156	        /* Разделение передачи на фрагменты, не охватывающие два блока. */
 25157	        while (m_in.nbytes != 0) {
 25158	
 25159	                off = (unsigned int) (position % block_size);/* смещение в блоке */
 25160	                if (partial_pipe) {  /* только для каналов */
 25161	                        chunk = MIN(partial_cnt, block_size - off);
 25162	                } else
 25163	                        chunk = MIN(m_in.nbytes, block_size - off);
 25164	                if (chunk < 0) chunk = block_size - off;
 25165	
 25166	                if (rw_flag == READING) {
 25167	                        bytes_left = f_size - position;
 25168	                        if (position >= f_size) break;  /* мы за пределами конца файла */
 25169	                        if (chunk > bytes_left) chunk = (int) bytes_left;
 25170	                }
 25171	
 25172	                /* Чтение или запись 'chunk' байт. */
 25173	                r = rw_chunk(rip, position, off, chunk, (unsigned) m_in.nbytes,
 25174	                             rw_flag, m_in.buffer, seg, usr, block_size, &completed);
 25175	
 25176	                if (r != OK) break;     /* достигнут конец файла */
 25177	                if (rdwt_err < 0) break;
 25178	
 25179	                /* Обновление счетчиков и указателей. */
 25180	                m_in.buffer += chunk;   /* адрес буфера пользователя */
 25181	                m_in.nbytes -= chunk;   /* число байтов, которые предстоит прочитать */
 25182	                cum_io += chunk;        /* число уже прочитанных байтов */
 25183	                position += chunk;      /* позиция внутри файла */
 25184	
 25185	                if (partial_pipe) {
 25186	                        partial_cnt -= chunk;
 25187	                        if (partial_cnt <= 0)  break;
 25188	                }
 25189	        }
 25190	  }
 25191	
 25192	  /* При записи обновление размера файла и времени доступа. */
 25193	  if (rw_flag == WRITING) {
 25194	        if (regular || mode_word == I_DIRECTORY) {
 25195	                if (position > f_size) rip->i_size = position;
 25196	        }
 25197	  } else {
 25198	        if (rip->i_pipe == I_PIPE) {
 25199	                if ( position >= rip->i_size) {
 25200	                        /* Сброс указателей канала. */
 25201	                        rip->i_size = 0;        /* данных не осталось */
 25202	                        position = 0;           /* сброс читающего (-их) */
 25203	                        wf = find_filp(rip, W_BIT);
 25204	                        if (wf != NIL_FILP) wf->filp_pos = 0;
 25205	                }
 25206	        }
 25207	  }
 25208	  f->filp_pos = position;
 25209	
 25210	  /* Проверка необходимости опережающего чтения; если чтение необходимо, его настройка. */
 25211	  if (rw_flag == READING && rip->i_seek == NO_SEEK && position % block_size== 0
 25212	                && (regular || mode_word == I_DIRECTORY)) {
 25213	        rdahed_inode = rip;
 25214	        rdahedpos = position;
 25215	  }
 25216	  rip->i_seek = NO_SEEK;
 25217	
 25218	  if (rdwt_err != OK) r = rdwt_err;     /* Проверка дисковых ошибок */
 25219	  if (rdwt_err == END_OF_FILE) r = OK;
 25220	
 25221	  /* если копирование в пространство пользователя или обратно завершилось неудачно, неудачей завершается вся операция чтения/записи. */
 25222	  if (r == OK && r2 != OK) {
 25223	        r = r2;
 25224	  }
 25225	  if (r == OK) {
 25226	        if (rw_flag == READING) rip->i_update |= ATIME;
 25227	        if (rw_flag == WRITING) rip->i_update |= CTIME | MTIME;
 25228	        rip->i_dirt = DIRTY;            /* теперь индексный узел модифицирован */
 25229	        if (partial_pipe) {
 25230	                partial_pipe = 0;
 25231	                        /* частичная запись в канал с */
 25232	                /* O_NONBLOCK,возврат счетчика записи */
 25233	                if (!(oflags & O_NONBLOCK)) {
 25234	                        fp->fp_cum_io_partial = cum_io;
 25235	                        suspend(XPIPE);   /* частичная запись в канал с */
 25236	                        return(SUSPEND);  /* nbyte > PIPE_SIZE - не атомарная*/
 25237	                }
 25238	        }
 25239	        fp->fp_cum_io_partial = 0;
 25240	        return(cum_io);
 25241	  }
 25242	  if (bufs_in_use < 0) {
 25243	        panic(__FILE__,"end - bufs_in_use negative", bufs_in_use);
 25244	  }
 25245	  return(r);
 25246	}
	
 25248	/*===========================================================================*
 25249	 *                              rw_chunk                                     *
 25250	 *===========================================================================*/
 25251	PRIVATE int rw_chunk(rip, position, off, chunk, left, rw_flag, buff,
 25252	 seg, usr, block_size, completed)
 25253	register struct inode *rip;     /* указатель на индексный узел для считываемого/записываемого файла */
 25254	off_t position;                 /* позиция для считывания/записи внутри файла */
 25255	unsigned off;                   /* смещение внутри текущего блока */
 25256	int chunk;                      /* число байтов для считывания/записи */
 25257	unsigned left;                  /* максимально число байтов после позиции */
 25258	int rw_flag;                    /* чтение или запись */
 25259	char *buff;                     /* виртуальный адрес буфера пользователя */
 25260	int seg;                        /* T- или D-сегмент в пространстве пользователя */
 25261	int usr;                        /* процесс пользователя */
 25262	int block_size;                 /* размер блока в файловой системе, которой принадлежит файл */
 25263	int *completed;                 /* число копируемых байтов */
 25264	{
 25265	/* Чтение или запись (части) блока. */
 25266	
 25267	  register struct buf *bp;
 25268	  register int r = OK;
 25269	  int n, block_spec;
 25270	  block_t b;
 25271	  dev_t dev;
 25272	
 25273	  *completed = 0;
 25274	
 25275	  block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
 25276	  if (block_spec) {
 25277	        b = position/block_size;
 25278	        dev = (dev_t) rip->i_zone[0];
 25279	  } else {
 25280	        b = read_map(rip, position);
 25281	        dev = rip->i_dev;
 25282	  }
 25283	
 25284	  if (!block_spec && b == NO_BLOCK) {
 25285	        if (rw_flag == READING) {
 25286	                /* Чтение из несуществующего блока. При считывании должны получаться нули.*/
 25287	                bp = get_block(NO_DEV, NO_BLOCK, NORMAL);    /* получение буфера */
 25288	                zero_block(bp);
 25289	        } else {
 25290	                /* Запись в несуществующий блок. Создание и ввод в индексный узел.*/
 25291	                if ((bp= new_block(rip, position)) == NIL_BUF)return(err_code);
 25292	        }
 25293	  } else if (rw_flag == READING) {
 25294	        /* Чтение и опережающее чтение. */
 25295	        bp = rahead(rip, b, position, left);
 25296	  } else {
 25297	        /* Обычно частично перезаписываемый блок сначала считывается. Однако
 25298	         * полный блок считывание не нужно. Если он имеется в кэше, получить его,
 25299	         * иначе выделить свободный буфер.
 25300	         */
 25301	        n = (chunk == block_size ? NO_READ :  NORMAL);
 25302	        if (!block_spec && off == 0 && position >= rip->i_size) n = NO_READ;
 25303	        bp = get_block(dev, b, n);
 25304	  }
 25305	
 25306	  /* Во всех случаях bp теперь указывает на допустимый буфер. */
 25307	  if (bp == NIL_BUF) {
 25308	        panic(__FILE__,"bp not valid in rw_chunk, this can't happen", NO_NUM);
 25309	  }
 25310	  if (rw_flag == WRITING && chunk != block_size && !block_spec &&
 25311	                                        position >= rip->i_size && off == 0) {
 25312	        zero_block(bp);
 25313	  }
 25314	
 25315	  if (rw_flag == READING) {
 25316	        /* Копирование фрагмента из буфера блоков в пространство пользователя. */
 25317	        r = sys_vircopy(FS_PROC_NR, D, (phys_bytes) (bp->b_data+off),
 25318	                        usr, seg, (phys_bytes) buff,
 25319	                        (phys_bytes) chunk);
 25320	  } else {
 25321	        /* Копирование фрагмента из пространства пользователя в буфер блоков. */
 25322	        r = sys_vircopy(usr, seg, (phys_bytes) buff,
 25323	                        FS_PROC_NR, D, (phys_bytes) (bp->b_data+off),
 25324	                        (phys_bytes) chunk);
 25325	        bp->b_dirt = DIRTY;
 25326	  }
 25327	  n = (off + chunk == block_size ? FULL_DATA_BLOCK :  PARTIAL_DATA_BLOCK);
 25328	  put_block(bp, n);
 25329	
 25330	  return(r);
 25331	}
	
	
 25334	/*===========================================================================*
 25335	 *                              read_map                                     *
 25336	 *===========================================================================*/
 25337	PUBLIC block_t read_map(rip, position)
 25338	register struct inode *rip;     /* указатель на индексный узел с требуемой структурой */
 25339	off_t position;                 /* позиция в файле, для которой нужно определить номер блока */
 25340	{
 25341	/* Поиск по позиции в файле и узлу номера блока (не зоны), в котором находится заданная
 25342	 * позиция внутри соответствующего файла, и возврат этого номера.
 25343	 */
 25344	
 25345	  register struct buf *bp;
 25346	  register zone_t z;
 25347	  int scale, boff, dzones, nr_indirects, index, zind, ex;
 25348	  block_t b;
 25349	  long excess, zone, block_pos;
 25350	  
 25351	  scale = rip->i_sp->s_log_zone_size;           /* для преобразования блока-зоны */
 25352	  block_pos = position/rip->i_sp->s_block_size; /* относительный номер блока в файле */
 25353	  zone = block_pos >> scale;                    /* зона позиции */
 25354	  boff = (int) (block_pos - (zone << scale) );  /* относительный номер блока внутри зоны */
 25355	  dzones = rip->i_ndzones;
 25356	  nr_indirects = rip->i_nindirs;
 25357	
 25358	  /* Должна ли позиция находиться в самом индексном узле? */
 25359	  if (zone < dzones) {
 25360	        zind = (int) zone;      /* индекс должен быть int */
 25361	        z = rip->i_zone[zind];
 25362	        if (z == NO_ZONE) return(NO_BLOCK);
 25363	        b = ((block_t) z << scale) + boff;
 25364	        return(b);
 25365	  }
 25366	
 25367	  /* Блок не в индексном узле, поэтому он должен быть лишь косвенным или дважды косвенным. */
 25368	  excess = zone - dzones;       /* первые Vx_NR_DZONES не учитывать */
 25369	
 25370	  if (excess < nr_indirects) {
 25371	        /* позиция может быть найдена через косвенный блок. */
 25372	        z = rip->i_zone[dzones];
 25373	  } else {
 25374	        /* позиция может быть найдена через дважды косвенный блок. */
 25375	        if ( (z = rip->i_zone[dzones+1]) == NO_ZONE) return(NO_BLOCK);
 25376	        excess -= nr_indirects;                 /* косвенный блок не дает результата */
 25377	        b = (block_t) z << scale;
 25378	        bp = get_block(rip->i_dev, b, NORMAL);  /* получение дважды косвенного блока  */
 25379	        index = (int) (excess/nr_indirects);
 25380	        z = rd_indir(bp, index);                /* z= зона для косвенного блока */
 25381	        put_block(bp, INDIRECT_BLOCK);          /* освобождение дважды косвенного блока */
 25382	        excess = excess % nr_indirects;         /* индекс в косвенном блоке */
 25383	  }
 25384	
 25385	  /* 'z' – номер зоны косвенного блока; 'excess' – индекс в нем. */
 25386	  if (z == NO_ZONE) return(NO_BLOCK);
 25387	  b = (block_t) z << scale;                     /* b - номер косвенного блока */
 25388	  bp = get_block(rip->i_dev, b, NORMAL);        /* получение косвенного блока */
 25389	  ex = (int) excess;                            /* необходим тип integer */
 25390	  z = rd_indir(bp, ex);                         /* получение указываемого блока */
 25391	  put_block(bp, INDIRECT_BLOCK);                /* освобождение косвенного блока */
 25392	  if (z == NO_ZONE) return(NO_BLOCK);
 25393	  b = ((block_t) z << scale) + boff;
 25394	  return(b);
 25395	}
	
 25397	/*===========================================================================*
 25398	 *                              rd_indir                                     *
 25399	 *===========================================================================*/
 25400	PUBLIC zone_t rd_indir(bp, index)
 25401	struct buf *bp;                 /* указатель на косвенный блок */
 25402	int index;                      /* индекс в *bp */
 25403	{
 25404	/* Чтение одной записи по указателю на косвенный блок. Выделение для этого отдельной
 25405	 * процедуры связано с наличием 4 вариантов:
 25406	 * V1 (IBM и 68000) и V2 (IBM и 68000).
 25407	 */
 25408	
 25409	  struct super_block *sp;
 25410	  zone_t zone;                  /* зоны V2 имеют тип longs (в V1 - short) */
 25411	
 25412	  sp = get_super(bp->b_dev);    /* для определения типа файловой системы нужен суперблок */
 25413	
 25414	  /* чтение зона из косвенного блока */
 25415	  if (sp->s_version == V1)
 25416	        zone = (zone_t) conv2(sp->s_native, (int)  bp->b_v1_ind[index]);
 25417	  else
 25418	        zone = (zone_t) conv4(sp->s_native, (long) bp->b_v2_ind[index]);
 25419	
 25420	  if (zone != NO_ZONE &&
 25421	                (zone < (zone_t) sp->s_firstdatazone || zone >= sp->s_zones)) {
 25422	        printf("Illegal zone number %ld in indirect block, index %d\n",
 25423	               (long) zone, index);
 25424	        panic(__FILE__,"check file system", NO_NUM);
 25425	  }
 25426	  return(zone);
 25427	}
	
 25429	/*===========================================================================*
 25430	 *                              read_ahead                                   *
 25431	 *===========================================================================*/
 25432	PUBLIC void read_ahead()
 25433	{
 25434	/* опережающее чтение блока в кэш . */
 25435	  int block_size;
 25436	  register struct inode *rip;
 25437	  struct buf *bp;
 25438	  block_t b;
 25439	
 25440	  rip = rdahed_inode;           /* указатель на индексный узел для опережающего чтения */
 25441	  block_size = get_block_size(rip->i_dev);
 25442	  rdahed_inode = NIL_INODE;     /* отключение опережающего чтения */
 25443	  if ( (b = read_map(rip, rdahedpos)) == NO_BLOCK) return;      /* в конце файла */
 25444	  bp = rahead(rip, b, rdahedpos, block_size);
 25445	  put_block(bp, PARTIAL_DATA_BLOCK);
 25446	}
	
 25448	/*===========================================================================*
 25449	 *                              rahead                                       *
 25450	 *===========================================================================*/
 25451	PUBLIC struct buf *rahead(rip, baseblock, position, bytes_ahead)
 25452	register struct inode *rip;     /* указатель на индексный узел считываемого файла */
 25453	block_t baseblock;              /* блок в текущей позиции */
 25454	off_t position;                 /* позиция внутри файла */
 25455	unsigned bytes_ahead;           /* байтов за позицией для непосредственного использования */
 25456	{
 25457	/* копирование блока из кэша или устройства. Если требуется физическое чтение, считывание
 25458	 * из кэша как можно большего числа блоков. Обычно считывается bytes_ahead байт и как
 25459	 * минимум BLOCKS_MINIMUM.
 25460	 * Драйвер устройства может взять процесс на свое усмотрение и прекратить чтение на границе
 25461	 * цилиндра или после ошибки. Для этого функция rw_scattered() устанавливает специальный
 25462	 * флаг при всех считываниях.
 25463	 */
 25464	  int block_size;
 25465	/* Минимальное число заранее считываемых блоков. */
 25466	# define BLOCKS_MINIMUM         (NR_BUFS < 50 ? 18 :  32)
 25467	  int block_spec, scale, read_q_size;
 25468	  unsigned int blocks_ahead, fragment;
 25469	  block_t block, blocks_left;
 25470	  off_t ind1_pos;
 25471	  dev_t dev;
 25472	  struct buf *bp;
 25473	  static struct buf *read_q[NR_BUFS];
 25474	
 25475	  block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
 25476	  if (block_spec) {
 25477	        dev = (dev_t) rip->i_zone[0];
 25478	  } else {
 25479	        dev = rip->i_dev;
 25480	  }
 25481	  block_size = get_block_size(dev);
 25482	
 25483	  block = baseblock;
 25484	  bp = get_block(dev, block, PREFETCH);
 25485	  if (bp->b_dev != NO_DEV) return(bp);
 25486	
 25487	  /* Оптимальное число блоков, считываемых заранее: много.
 25488	   * Спрогнозировать геометрию устройства невозможно, поэтому предоставим работу с ней
 25489	   * драйверу.
 25490	   *
 25491	   * Драйвер дисковода для дискет может считывать полную дорожку без задержки вращения и
 25492	   * по возможности избегает частичных считываний, поэтому лучше всего, если заранее будут
 25493	   * считаны блоки двух дорожек (двух потому, что некоторые типы дискет имеют нечетное
 25494	   * число секторов на дорожке и блок может находиться на двух дорожках).
 25495	   *
 25496	   * Драйверы дисков не пытаются быть умными. В современных дисках предугадать реальную 
 25497	   * геометрию невозможно, поэтому лучше считывать столько данных, сколько удается.
 25498	   * К счастью, кэширование на диске дает немного времени на то, чтобы начать следующее
 25499	   * считывание.
 25500	   *
 25501	   * В решении, приведеннои далее, есть трюки. Блоки считываются с текущей позиции
 25502	   * файла в надежде, что удастся найти больше блоков, принадлежащих этому файлу. В более
 25503	   * удачном решении нужно просматривать уже доступные указатели зон и косвенные блоки
 25504	   * (но не вызывать read_map!).
 25505	   */
 25506	
 25507	  fragment = position % block_size;
 25508	  position -= fragment;
 25509	  bytes_ahead += fragment;
 25510	
 25511	  blocks_ahead = (bytes_ahead + block_size - 1) / block_size;
 25512	
 25513	  if (block_spec && rip->i_size == 0) {
 25514	        blocks_left = NR_IOREQS;
 25515	  } else {
 25516	        blocks_left = (rip->i_size - position + block_size - 1) / block_size;
 25517	
 25518	        /* выбор первого косвенного блока, если мы поблизости. */
 25519	        if (!block_spec) {
 25520	                scale = rip->i_sp->s_log_zone_size;
 25521	                ind1_pos = (off_t) rip->i_ndzones * (block_size << scale);
 25522	                if (position <= ind1_pos && rip->i_size > ind1_pos) {
 25523	                        blocks_ahead++;
 25524	                        blocks_left++;
 25525	                }
 25526	        }
 25527	  }
 25528	
 25529	  /* Не более чем максимальное число запросов. */
 25530	  if (blocks_ahead > NR_IOREQS) blocks_ahead = NR_IOREQS;
 25531	
 25532	  /* Считывание хотя бы минимального числа блоков, но не после поиска */
 25533	  if (blocks_ahead < BLOCKS_MINIMUM && rip->i_seek == NO_SEEK)
 25534	        blocks_ahead = BLOCKS_MINIMUM;
 25535	
 25536	  /* Нельзя выходить за пределы файла */
 25537	  if (blocks_ahead > blocks_left) blocks_ahead = blocks_left;
 25538	
 25539	  read_q_size = 0;
 25540	
 25541	  /* Получение буферов блоков */
 25542	  for (;;) {
 25543	        read_q[read_q_size++] = bp;
 25544	
 25545	        if (--blocks_ahead == 0) break;
 25546	
 25547	        /* Не захламлять кэш, оставить 4 буфера свободными */
 25548	        if (bufs_in_use >= NR_BUFS - 4) break;
 25549	
 25550	        block++;
 25551	
 25552	        bp = get_block(dev, block, PREFETCH);
 25553	        if (bp->b_dev != NO_DEV) {
 25554	                /* Блок уже в кэше, извлекаем */
 25555	                put_block(bp, FULL_DATA_BLOCK);
 25556	                break;
 25557	        }
 25558	  }
 25559	  rw_scattered(dev, read_q, read_q_size, READING);
 25560	  return(get_block(dev, baseblock, NORMAL));
 25561	}




++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/write.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 25600	/* Этот файл – двойник "read.c". Он содержит код для записи, которого нет в 
 25601	 * read_write().
 25602	 *
 25603	 * Файл имеет следующие точки входа
 25604	 *   do_write:      вызов read_write для выполнения системного вызова WRITE
 25605	 *   clear_zone:    стирание зоны в середине файла
 25606	 *   new_block:     получение нового блока
 25607	 */
 25608	
 25609	#include "fs.h"
 25610	#include <string.h>
 25611	#include "buf.h"
 25612	#include "file.h"
 25613	#include "fproc.h"
 25614	#include "inode.h"
 25615	#include "super.h"
 25616	
 25617	FORWARD _PROTOTYPE( int write_map, (struct inode *rip, off_t position,
 25618	                        zone_t new_zone)                                );
 25619	
 25620	FORWARD _PROTOTYPE( void wr_indir, (struct buf *bp, int index, zone_t zone) );
 25621	
 25622	/*===========================================================================*
 25623	 *                              do_write                                     *
 25624	 *===========================================================================*/
 25625	PUBLIC int do_write()
 25626	{
 25627	/* Выполнение системного вызова write(fd, buffer, nbytes)*/
 25628	
 25629	  return(read_write(WRITING));
 25630	}
	
 25632	/*===========================================================================*
 25633	 *                              write_map                                    *
 25634	 *===========================================================================*/
 25635	PRIVATE int write_map(rip, position, new_zone)
 25636	register struct inode *rip;     /* указатель на изменяемый индексный узел */
 25637	off_t position;                 /* адрес файла */
 25638	zone_t new_zone;                /* номер вставляемой зоны */
 25639	{
 25640	/* Запись новой зоны в индексный узел */
 25641	  int scale, ind_ex, new_ind, new_dbl, zones, nr_indirects, single, zindex, ex;
 25642	  zone_t z, z1;
 25643	  register block_t b;
 25644	  long excess, zone;
 25645	  struct buf *bp;
 25646	
 25647	  rip->i_dirt = DIRTY;          /* индексный узел будет изменен */
 25648	  bp = NIL_BUF;
 25649	  scale = rip->i_sp->s_log_zone_size;           /* для преобразования зоны в блок */
 25650	        /* относительный номер вставляемой зоны */
 25651	  zone = (position/rip->i_sp->s_block_size) >> scale;
 25652	  zones = rip->i_ndzones;        /* число прямых зон в индексном узле */
 25653	  nr_indirects = rip->i_nindirs; /* число косвенных зон в косвенном блоке */
 25654	
 25655	  /* Находится ли позиция в самом индексном узле? */
 25656	  if (zone < zones) {
 25657	        zindex = (int) zone;    /* здесь нужно значение integer */
 25658	        rip->i_zone[zindex] = new_zone;
 25659	        return(OK);
 25660	  }
 25661	
 25662	  /* зона не в индексном узле, поэтому она косвенная или дважды косвенная. */
 25663	  excess = zone - zones;        /* первые Vx_NR_DZONES не учитывать */
 25664	  new_ind = FALSE;
 25665	  new_dbl = FALSE;
 25666	
 25667	  if (excess < nr_indirects) {
 25668	        /* позиция может быть найдена через косвенный блок. */
 25669	        z1 = rip->i_zone[zones];        /* косвенная зона*/
 25670	        single = TRUE;
 25671	  } else {
 25672	        /* позиция может быть найдена через дважды косвенный блок. */
 25673	        if ( (z = rip->i_zone[zones+1]) == NO_ZONE) {
 25674	                /* создание дважды косвенного блока. */
 25675	                if ( (z = alloc_zone(rip->i_dev, rip->i_zone[0])) == NO_ZONE)
 25676	                        return(err_code);
 25677	                rip->i_zone[zones+1] = z;
 25678	                new_dbl = TRUE; /* установка флага */
 25679	        }
 25680	
 25681	        /* В любом случае, 'z' - номер зоны дважды косвенного блока. */
 25682	        excess -= nr_indirects; /* косвенная не считается */
 25683	        ind_ex = (int) (excess / nr_indirects);
 25684	        excess = excess % nr_indirects;
 25685	        if (ind_ex >= nr_indirects) return(EFBIG);
 25686	        b = (block_t) z << scale;
 25687	        bp = get_block(rip->i_dev, b, (new_dbl ? NO_READ :  NORMAL));
 25688	        if (new_dbl) zero_block(bp);
 25689	        z1 = rd_indir(bp, ind_ex);
 25690	        single = FALSE;
 25691	  }
 25692	
 25693	  /* z1 - косвенная зона; 'excess' - индекс. */
 25694	  if (z1 == NO_ZONE) {
 25695	        /* Создание косвенного блока и сохранение номера зоны в индексном узле или дважды косвенном блоке. */
 25696	        z1 = alloc_zone(rip->i_dev, rip->i_zone[0]);
 25697	        if (single)
 25698	                rip->i_zone[zones] = z1;        /* обновление индексного узла */
 25699	        else
 25700	                wr_indir(bp, ind_ex, z1);       /* обновление дважды косвенного блока */
 25701	
 25702	        new_ind = TRUE;
 25703	        if (bp != NIL_BUF) bp->b_dirt = DIRTY;  /* если дважды косвенный блок, он модифицирован */
 25704	        if (z1 == NO_ZONE) {
 25705	                put_block(bp, INDIRECT_BLOCK);  /* освободить дважды косвенный блок */
 25706	                return(err_code);       /* не удалось создать косвенный блок */
 25707	        }
 25708	  }
 25709	  put_block(bp, INDIRECT_BLOCK);        /* освобождение дважды косвенного блока  */
 25710	
 25711	  /* z1 – номер зоны косвенного блока */
 25712	  b = (block_t) z1 << scale;
 25713	  bp = get_block(rip->i_dev, b, (new_ind ? NO_READ :  NORMAL) );
 25714	  if (new_ind) zero_block(bp);
 25715	  ex = (int) excess;                    /* здесь нужно значение int */
 25716	  wr_indir(bp, ex, new_zone);
 25717	  bp->b_dirt = DIRTY;
 25718	  put_block(bp, INDIRECT_BLOCK);
 25719	
 25720	  return(OK);
 25721	}
	
 25723	/*===========================================================================*
 25724	 *                              wr_indir                                     *
 25725	 *===========================================================================*/
 25726	PRIVATE void wr_indir(bp, index, zone)
 25727	struct buf *bp;                 /* указатель на косвенный блок */
 25728	int index;                      /* индекс *bp */
 25729	zone_t zone;                    /* зона для записи */
 25730	{
 25731	/* Запись одного элемента по указателю на косвенный блок. */
 25732	
 25733	  struct super_block *sp;
 25734	
 25735	  sp = get_super(bp->b_dev);    /* для определения типа файловой системы нужен суперблок */
 25736	
 25737	  /* запись зоны в косвенный блок */
 25738	  if (sp->s_version == V1)
 25739	        bp->b_v1_ind[index] = (zone1_t) conv2(sp->s_native, (int)  zone);
 25740	  else
 25741	        bp->b_v2_ind[index] = (zone_t)  conv4(sp->s_native, (long) zone);
 25742	}
	
 25744	/*===========================================================================*
 25745	 *                              clear_zone                                   *
 25746	 *===========================================================================*/
 25747	PUBLIC void clear_zone(rip, pos, flag)
 25748	register struct inode *rip;     /* очищаемый индексный узел */
 25749	off_t pos;                      /* указывает на очищаемый блок */
 25750	int flag;                       /* 0 если вызывается функцией read_write, 1 – если функцией new_block */
 25751	{
 25752	/* Обнуление зоны, возможно с середины. Параметр 'pos' - байт первого обнуляемого блока.
 25753	 * Функция Clearzone() вызывается из функций read_write and new_block().
 25754	 *
 25755	 */
 25756	
 25757	  register struct buf *bp;
 25758	  register block_t b, blo, bhi;
 25759	  register off_t next;
 25760	  register int scale;
 25761	  register zone_t zone_size;
 25762	
 25763	  /* Если размер блока совпадает с размером зоны, функция clear_zone() не нужна. */
 25764	  scale = rip->i_sp->s_log_zone_size;
 25765	  if (scale == 0) return;
 25766	
 25767	  zone_size = (zone_t) rip->i_sp->s_block_size << scale;
 25768	  if (flag == 1) pos = (pos/zone_size) * zone_size;
 25769	  next = pos + rip->i_sp->s_block_size - 1;
 25770	
 25771	  /* Если 'pos' находится в последнем блоке зоны, не очищать зону. */
 25772	  if (next/zone_size != pos/zone_size) return;
 25773	  if ( (blo = read_map(rip, next)) == NO_BLOCK) return;
 25774	  bhi = (  ((blo>>scale)+1) << scale)   - 1;
 25775	
 25776	  /* Очистить все блоки между 'blo' и 'bhi'. */
 25777	  for (b = blo; b <= bhi; b++) {
 25778	        bp = get_block(rip->i_dev, b, NO_READ);
 25779	        zero_block(bp);
 25780	        put_block(bp, FULL_DATA_BLOCK);
 25781	  }
 25782	}
	
 25784	/*===========================================================================*
 25785	 *                              new_block                                    *
 25786	 *===========================================================================*/
 25787	PUBLIC struct buf *new_block(rip, position)
 25788	register struct inode *rip;     /* указатель на индексный узел */
 25789	off_t position;                 /* файловый указатель */
 25790	{
 25791	/* Получение нового блока и возврат указателя на него. Это может потребовать выделения
 25792	 * целой зоны и затем возвращения начального блока.
 25793	 * В то же время в текущей зоне могут находиться неиспользуемые блоки.
 25794	 */
 25795	
 25796	  register struct buf *bp;
 25797	  block_t b, base_block;
 25798	  zone_t z;
 25799	  zone_t zone_size;
 25800	  int scale, r;
 25801	  struct super_block *sp;
 25802	
 25803	  /* Имеется ли доступный блок в текущей зоне? */
 25804	  if ( (b = read_map(rip, position)) == NO_BLOCK) {
 25805	        /* По возможности выбор первой зоны. */
 25806	        /* Неудача, если файл не пуст, но номер первой зоны - NO_ZONE означает,
 25807	         * что зона состоит из нулей. Лучше поискать рядом последнюю реальную
 25808	         * зону.
 25809	         */
 25810	        if (rip->i_zone[0] == NO_ZONE) {
 25811	                sp = rip->i_sp;
 25812	                z = sp->s_firstdatazone;
 25813	        } else {
 25814	                z = rip->i_zone[0];     /* поиск рядом с первой зоной */
 25815	        }
 25816	        if ( (z = alloc_zone(rip->i_dev, z)) == NO_ZONE) return(NIL_BUF);
 25817	        if ( (r = write_map(rip, position, z)) != OK) {
 25818	                free_zone(rip->i_dev, z);
 25819	                err_code = r;
 25820	                return(NIL_BUF);
 25821	        }
 25822	
 25823	        /* Если мы не пишем в конец файла, очистка зоны для гарантии. */
 25824	        if ( position != rip->i_size) clear_zone(rip, position, 1);
 25825	        scale = rip->i_sp->s_log_zone_size;
 25826	        base_block = (block_t) z << scale;
 25827	        zone_size = (zone_t) rip->i_sp->s_block_size << scale;
 25828	        b = base_block + (block_t)((position % zone_size)/rip->i_sp->s_block_size);
 25829	  }
 25830	
 25831	  bp = get_block(rip->i_dev, b, NO_READ);
 25832	  zero_block(bp);
 25833	  return(bp);
 25834	}
	
 25836	/*===========================================================================*
 25837	 *                              zero_block                                   *
 25838	 *===========================================================================*/
 25839	PUBLIC void zero_block(bp)
 25840	register struct buf *bp;        /* указатель на обнуляемый буфер */
 25841	{
 25842	/* Обнуление блока. */
 25843	  memset(bp->b_data, 0, MAX_BLOCK_SIZE);
 25844	  bp->b_dirt = DIRTY;
 25845	}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/pipe.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 25900	/* Этот файл обеспечивает приостановку и восстановление процессов. Процесс может быть
 25901	 * приостановлен, если собирается, но не может выполнить чтение из канала или специального файла 
 25902	 * или запись в канал или специальный файл. Если продолжение процесса невозможно, он приостанавливается 
 25903	 * и впоследствии восстанавливается, когда становится возможным дальнейшее выполнение.
 25904	 *
 25905	 *
 25906	 * Файл имеет следующие точки входа
 25907	 *   do_pipe:      выполнение системного вызова PIPE
 25908	 *   pipe_check:   проверка возможности чтения из канала или записи в канал
 25909	 *   suspend:      приостановка процесса, не способного выполнить требуемое чтение или запись
 25910	 *   release:      проверка возможности возобновления приостановленного процесса и ее
 25911	 *                 осуществление
 25912	 *   revive:       пометка приостановленного ранее процесса как готового к выполнению
 25913	 *   do_unpause:   процессу послан сигнал; проверка, приостановлен ли процесс
 25914	 */
 25915	
 25916	#include "fs.h"
 25917	#include <fcntl.h>
 25918	#include <signal.h>
 25919	#include <minix/callnr.h>
 25920	#include <minix/com.h>
 25921	#include <sys/select.h>
 25922	#include <sys/time.h>
 25923	#include "file.h"
 25924	#include "fproc.h"
 25925	#include "inode.h"
 25926	#include "param.h"
 25927	#include "super.h"
 25928	#include "select.h"
 25929	
 25930	/*===========================================================================*
 25931	 *                              do_pipe                                      *
 25932	 *===========================================================================*/
 25933	PUBLIC int do_pipe()
 25934	{
 25935	/* Выполнение системного вызова pipe(fil_des). */
 25936	
 25937	  register struct fproc *rfp;
 25938	  register struct inode *rip;
 25939	  int r;
 25940	  struct filp *fil_ptr0, *fil_ptr1;
 25941	  int fil_des[2];               /* сюда помещается ответ */
 25942	
 25943	  /* Получение двух дескрипторов файлов. */
 25944	  rfp = fp;
 25945	  if ( (r = get_fd(0, R_BIT, &fil_des[0], &fil_ptr0)) != OK) return(r);
 25946	  rfp->fp_filp[fil_des[0]] = fil_ptr0;
 25947	  fil_ptr0->filp_count = 1;
 25948	  if ( (r = get_fd(0, W_BIT, &fil_des[1], &fil_ptr1)) != OK) {
 25949	        rfp->fp_filp[fil_des[0]] = NIL_FILP;
 25950	        fil_ptr0->filp_count = 0;
 25951	        return(r);
 25952	  }
 25953	  rfp->fp_filp[fil_des[1]] = fil_ptr1;
 25954	  fil_ptr1->filp_count = 1;
 25955	
 25956	  /* Создание индексного узла на устройстве канала. */
 25957	  if ( (rip = alloc_inode(root_dev, I_REGULAR) ) == NIL_INODE) {
 25958	        rfp->fp_filp[fil_des[0]] = NIL_FILP;
 25959	        fil_ptr0->filp_count = 0;
 25960	        rfp->fp_filp[fil_des[1]] = NIL_FILP;
 25961	        fil_ptr1->filp_count = 0;
 25962	        return(err_code);
 25963	  }
 25964	
 25965	  if (read_only(rip) != OK) 
 25966	        panic(__FILE__,"pipe device is read only", NO_NUM);
 25967	 
 25968	  rip->i_pipe = I_PIPE;
 25969	  rip->i_mode &= ~I_REGULAR;
 25970	  rip->i_mode |= I_NAMED_PIPE;  /* этот бит установлен для каналов и FIFO */
 25971	  fil_ptr0->filp_ino = rip;
 25972	  fil_ptr0->filp_flags = O_RDONLY;
 25973	  dup_inode(rip);               /* для двойного использования */
 25974	  fil_ptr1->filp_ino = rip;
 25975	  fil_ptr1->filp_flags = O_WRONLY;
 25976	  rw_inode(rip, WRITING);       /* пометка индексного узла как выделенного */
 25977	  m_out.reply_i1 = fil_des[0];
 25978	  m_out.reply_i2 = fil_des[1];
 25979	  rip->i_update = ATIME | CTIME | MTIME;
 25980	  return(OK);
 25981	}
	
 25983	/*===========================================================================*
 25984	 *                              pipe_check                                   *
 25985	 *===========================================================================*/
 25986	PUBLIC int pipe_check(rip, rw_flag, oflags, bytes, position, canwrite, notouch)
 25987	register struct inode *rip;     /* индексный узел канала */
 25988	int rw_flag;                    /* чтение или запись */
 25989	int oflags;                     /* флаги, устанавливаемые open или fcntl */
 25990	register int bytes;             /* байты для чтения или записи */
 25991	register off_t position;        /* текущая позиция в файле */
 25992	int *canwrite;                  /* возврат: число байтов, которые мы можем записать */
 25993	int notouch;                    /* только проверка */
 25994	{
 25995	/* Если процесс читает из пустого канала, в который кто-то пишет,
 25996	 * приостановить его. Если канал пуст и в него никто не пишет,
 25997	 * вернуть 0 байт. Если процесс ведет запись в канал и никто не
 25998	 * читает из него, вернуть ошибку "разорванный канал".
 25999	 */
 26000	
 26001	  /* Проверка пустого канала при чтении. */
 26002	  if (rw_flag == READING) {
 26003	        if (position >= rip->i_size) {
 26004	                /* Процесс читает из пустого канала. */
 26005	                int r = 0;
 26006	                if (find_filp(rip, W_BIT) != NIL_FILP) {
 26007	                        /* Имеется процесс, записывающий в канал */
 26008	                        if (oflags & O_NONBLOCK) {
 26009	                                r = EAGAIN;
 26010	                        } else {
 26011	                                if (!notouch)
 26012	                                        suspend(XPIPE); /* блокирование читающего процесса */
 26013	                                r = SUSPEND;
 26014	                        }
 26015	                        /* если нужно, активировать приостановленные процессы, записывающие в канал. */
 26016	                        if (susp_count > 0 && !notouch)
 26017	                                release(rip, WRITE, susp_count);
 26018	                }
 26019	                return(r);
 26020	        }
 26021	  } else {
 26022	        /* Процесс записывает в канал. */
 26023	        if (find_filp(rip, R_BIT) == NIL_FILP) {
 26024	                /* Указать ядру сгенерировать сигнал SIGPIPE. */
 26025	                if (!notouch)
 26026	                        sys_kill((int)(fp - fproc), SIGPIPE);
 26027	                return(EPIPE);
 26028	        }
 26029	
 26030	        if (position + bytes > PIPE_SIZE(rip->i_sp->s_block_size)) {
 26031	                if ((oflags & O_NONBLOCK)
 26032	                 && bytes < PIPE_SIZE(rip->i_sp->s_block_size))
 26033	                        return(EAGAIN);
 26034	                else if ((oflags & O_NONBLOCK)
 26035	                && bytes > PIPE_SIZE(rip->i_sp->s_block_size)) {
 26036	                if ( (*canwrite = (PIPE_SIZE(rip->i_sp->s_block_size) 
 26037	                        - position)) > 0)  {
 26038	                                /* Выполнение частичной записи. Читающий процесс нужно разбудить*/
 26039	                                if (!notouch)
 26040	                                        release(rip, READ, susp_count);
 26041	                                return(1);
 26042	                        } else {
 26043	                                return(EAGAIN);
 26044	                        }
 26045	                     }
 26046	                if (bytes > PIPE_SIZE(rip->i_sp->s_block_size)) {
 26047	                        if ((*canwrite = PIPE_SIZE(rip->i_sp->s_block_size) 
 26048	                                - position) > 0) {
 26049	                                /* Выполнение частичной записи. Читающий процесс нужно разбудить,
 26050	                                 * поскольку мы приостановимся в read_write()
 26051	                                 */
 26052	                                release(rip, READ, susp_count);
 26053	                                return(1);
 26054	                        }
 26055	                }
 26056	                if (!notouch)
 26057	                        suspend(XPIPE); /* остановить пишущий процесс -- канал полон */
 26058	                return(SUSPEND);
 26059	        }
 26060	
 26061	        /* Запись в пустой канал. Поиск приостановленного читающего процесса. */
 26062	        if (position == 0 && !notouch)
 26063	                release(rip, READ, susp_count);
 26064	  }
 26065	
 26066	  *canwrite = 0;
 26067	  return(1);
 26068	}
	
 26070	/*===========================================================================*
 26071	 *                              suspend                                      *
 26072	 *===========================================================================*/
 26073	PUBLIC void suspend(task)
 26074	int task;                       /* кого ждет процесс? (PIPE = канал) */
 26075	{
 26076	/* Принимаем меры для приостановки обработки текущего системного вызова. Параметры
 26077	 * сохраняются в таблице процессов для использования после возобновления
 26078	 * (на самом деле, они не используются, когда процесс ожидает устройство ввода-вывода,
 26079	 * однако они нужны для каналов, и выполнять разграничение не стоит).
 26080	 * После вызова suspend() должна возвращаться псевдоошибка SUSPEND.
 26081	 */
 26082	
 26083	  if (task == XPIPE || task == XPOPEN) susp_count++; /* номер процесса, приостановленного на канале */
 26084	  fp->fp_suspended = SUSPENDED;
 26085	  fp->fp_fd = m_in.fd << 8 | call_nr;
 26086	  fp->fp_task = -task;
 26087	  if (task == XLOCK) {
 26088	        fp->fp_buffer = (char *) m_in.name1;    /* третий аргумент fcntl() */
 26089	        fp->fp_nbytes = m_in.request;           /* второй аргумент fcntl() */
 26090	  } else {
 26091	        fp->fp_buffer = m_in.buffer;            /* для чтения и записи */
 26092	        fp->fp_nbytes = m_in.nbytes;
 26093	  }
 26094	}
	
 26096	/*===========================================================================*
 26097	 *                              release                                      *
 26098	 *===========================================================================*/
 26099	PUBLIC void release(ip, call_nr, count)
 26100	register struct inode *ip;      /* индексный узел канала */
 26101	int call_nr;                    /* READ, WRITE, OPEN или CREAT */
 26102	int count;                      /* максимальное число возобновляемых процессов */
 26103	{
 26104	/* Проверка наличия процессов, приостановленных каналом с индексным узлом 'ip'. Если такой
 26105	 * процесс есть и пытался выполнить запрос 'call_nr', возобновить процесс.
 26106	 *
 26107	 */
 26108	
 26109	  register struct fproc *rp;
 26110	  struct filp *f;
 26111	
 26112	  /* Попытка выполнить вызов также включает выбор операции 
 26113	   *
 26114	   */
 26115	  if (call_nr == READ || call_nr == WRITE) {
 26116	          int op;
 26117	          if (call_nr == READ)
 26118	                op = SEL_RD;
 26119	          else
 26120	                op = SEL_WR;
 26121	          for(f = &filp[0]; f < &filp[NR_FILPS]; f++) {
 26122	                if (f->filp_count < 1 || !(f->filp_pipe_select_ops & op) ||
 26123	                   f->filp_ino != ip)
 26124	                        continue;
 26125	                 select_callback(f, op);
 26126	                f->filp_pipe_select_ops &= ~op;
 26127	        }
 26128	  }
 26129	
 26130	  /* Поиск в таблице процессов. */
 26131	  for (rp = &fproc[0]; rp < &fproc[NR_PROCS]; rp++) {
 26132	        if (rp->fp_suspended == SUSPENDED &&
 26133	                        rp->fp_revived == NOT_REVIVING &&
 26134	                        (rp->fp_fd & BYTE) == call_nr &&
 26135	                        rp->fp_filp[rp->fp_fd>>8]->filp_ino == ip) {
 26136	                revive((int)(rp - fproc), 0);
 26137	                susp_count--;   /* отслеживание, какие процессы приостановлены */
 26138	                if (--count == 0) return;
 26139	        }
 26140	  }
 26141	}
	
 26143	/*===========================================================================*
 26144	 *                              revive                                       *
 26145	 *===========================================================================*/
 26146	PUBLIC void revive(proc_nr, returned)
 26147	int proc_nr;                    /* возобновляемый процесс */
 26148	int returned;                   /* число считанных байтов */
 26149	{
 26150	/* Возобновление приостановленного процесса. Если процесс приостановлен терминалом,
 26151	 * именно здесь происходит его возобновление.
 26152	 */
 26153	
 26154	  register struct fproc *rfp;
 26155	  register int task;
 26156	
 26157	  if (proc_nr < 0 || proc_nr >= NR_PROCS)
 26158	        panic(__FILE__,"revive err", proc_nr);
 26159	  rfp = &fproc[proc_nr];
 26160	  if (rfp->fp_suspended == NOT_SUSPENDED || rfp->fp_revived == REVIVING)return;
 26161	
 26162	  /* Флан 'reviving' применяется только к каналам. Процессы, ожидающие терминала, немедленно 
 26163	   * получают сообщение. Возобновление для каналов и терминалов различается.
 26164	   * Для select и терминалов возобновление уже завершено, а для каналов нет: 
 26165	   * процесс нужно перезапустить, чтобы дать ему возможность совершить повторную попытку.
 26166	   */
 26167	  task = -rfp->fp_task;
 26168	  if (task == XPIPE || task == XLOCK) {
 26169	        /* Возобновление процесса, приостановленного каналом или заблокированного. */
 26170	        rfp->fp_revived = REVIVING;
 26171	        reviving++;             /* процесс был блокирован или ожидал канала */
 26172	  } else {
 26173	        rfp->fp_suspended = NOT_SUSPENDED;
 26174	        if (task == XPOPEN) /* Процесс блокирован выполнением open или create */
 26175	                reply(proc_nr, rfp->fp_fd>>8);
 26176	        else if (task == XSELECT) {
 26177	                reply(proc_nr, returned);
 26178	        } else {
 26179	                /* Возобновление процесса, ожидающего канал или другое устройство. */
 26180	                rfp->fp_nbytes = returned;      /* притворяемся, что он хочет только того, что есть */
 26181	                reply(proc_nr, returned);       /* разблокирование процесса */
 26182	        }
 26183	  }
 26184	}
	
 26186	/*===========================================================================*
 26187	 *                              do_unpause                                   *
 26188	 *===========================================================================*/
 26189	PUBLIC int do_unpause()
 26190	{
 26191	/* Пользователю послан сигнал во время ожидания файловой системы.
 26192	 * Прерывание системного вызова с сообщением об ошибке EINTR.
 26193	 */
 26194	
 26195	  register struct fproc *rfp;
 26196	  int proc_nr, task, fild;
 26197	  struct filp *f;
 26198	  dev_t dev;
 26199	  message mess;
 26200	
 26201	  if (who > PM_PROC_NR) return(EPERM);
 26202	  proc_nr = m_in.pro;
 26203	  if (proc_nr < 0 || proc_nr >= NR_PROCS)
 26204	        panic(__FILE__,"unpause err 1", proc_nr);
 26205	  rfp = &fproc[proc_nr];
 26206	  if (rfp->fp_suspended == NOT_SUSPENDED) return(OK);
 26207	  task = -rfp->fp_task;
 26208	
 26209	  switch (task) {
 26210	        case XPIPE:              /* процесс, пытающийся читать из канала или писать в канал */
 26211	                break;
 26212	
 26213	        case XLOCK:              /* процесс,пытающийся установить блокировку с помощью FCNTL */
 26214	                break;
 26215	
 26216	        case XSELECT:            /* процесс, блокированный select() */
 26217	                select_forget(proc_nr);
 26218	                break;
 26219	
 26220	        case XPOPEN:             /* процесс, пытающийся открыть fifo */
 26221	                break;
 26222	
 26223	        default:                 /* process пытающийся выполнить ввод с устройства или вывод на устройство (например, терминал)*/
 26224	                fild = (rfp->fp_fd >> 8) & BYTE; /* извлечение дескриптора файла */
 26225	                if (fild < 0 || fild >= OPEN_MAX)
 26226	                        panic(__FILE__,"unpause err 2",NO_NUM);
 26227	                f = rfp->fp_filp[fild];
 26228	                dev = (dev_t) f->filp_ino->i_zone[0];   /* ожидаемое устройств */
 26229	                mess.TTY_LINE = (dev >> MINOR) & BYTE;
 26230	                mess.PROC_NR = proc_nr;
 26231	
 26232	                /* Указание ядру читать или писать. Режим заимствован из текущего вызова. */
 26233	                mess.COUNT = (rfp->fp_fd & BYTE) == READ ? R_BIT :  W_BIT;
 26234	                mess.m_type = CANCEL;
 26235	                fp = rfp;       /* трюк - ctty_io использует fp */
 26236	                (*dmap[(dev >> MAJOR) & BYTE].dmap_io)(task, &mess);
 26237	  }
 26238	
 26239	  rfp->fp_suspended = NOT_SUSPENDED;
 26240	  reply(proc_nr, EINTR);        /* вызов прерван сигналом */
 26241	  return(OK);
 26242	}
	
 26244	/*===========================================================================*
 26245	 *                              select_request_pipe                          *
 26246	 *===========================================================================*/
 26247	PUBLIC int select_request_pipe(struct filp *f, int *ops, int block)
 26248	{
 26249	        int orig_ops, r = 0, err, canwrite;
 26250	        orig_ops = *ops;
 26251	        if ((*ops & SEL_RD)) {
 26252	                if ((err = pipe_check(f->filp_ino, READING, 0,
 26253	                        1, f->filp_pos, &canwrite, 1)) != SUSPEND)
 26254	                        r |= SEL_RD;
 26255	                if (err < 0 && err != SUSPEND && (*ops & SEL_ERR))
 26256	                        r |= SEL_ERR;
 26257	        }
 26258	        if ((*ops & SEL_WR)) {
 26259	                if ((err = pipe_check(f->filp_ino, WRITING, 0,
 26260	                        1, f->filp_pos, &canwrite, 1)) != SUSPEND)
 26261	                        r |= SEL_WR;
 26262	                if (err < 0 && err != SUSPEND && (*ops & SEL_ERR))
 26263	                        r |= SEL_ERR;
 26264	        }
 26265	
 26266	        *ops = r;
 26267	
 26268	        if (!r && block) {
 26269	                f->filp_pipe_select_ops |= orig_ops;
 26270	        }
 26271	
 26272	        return SEL_OK;
 26273	}
	
 26275	/*===========================================================================*
 26276	 *                              select_match_pipe                            *
 26277	 *===========================================================================*/
 26278	PUBLIC int select_match_pipe(struct filp *f)
 26279	{
 26280	        /* распознание канала или именованного канала (FIFO) */
 26281	        if (f && f->filp_ino && (f->filp_ino->i_mode & I_NAMED_PIPE))
 26282	                return 1;
 26283	        return 0;
 26284	}
	





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/path.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 26300	/* Этот файл содержит процедуры, выполняющие поиск путей в системе каталогрв и
 26301	 * определяющие индексный узел, соответствующий заданному пути.
 26302	 *
 26303	 *  Файл имеет следующие точки входа
 26304	 *   eat_path:    главная процедура механизма преобразования пути в индексный узел
 26305	 *   last_dir:    поиск последнего каталога в заданном пути
 26306	 *   advance:     разбор одного компонента пути
 26307	 *   search_dir:  поиск строки в каталоге и возврат номера ее индексного узла
 26308	 */
 26309	
 26310	#include "fs.h"
 26311	#include <string.h>
 26312	#include <minix/callnr.h>
 26313	#include "buf.h"
 26314	#include "file.h"
 26315	#include "fproc.h"
 26316	#include "inode.h"
 26317	#include "super.h"
 26318	
 26319	PUBLIC char dot1[2] = ".";      /* используется search_dir для обхода разрешений */
 26320	PUBLIC char dot2[3] = "..";     /* доступа к каталогам  . и ..                 */
 26321	
 26322	FORWARD _PROTOTYPE( char *get_name, (char *old_name, char string [NAME_MAX]) );
 26323	
 26324	/*===========================================================================*
 26325	 *                              eat_path                                     *
 26326	 *===========================================================================*/
 26327	PUBLIC struct inode *eat_path(path)
 26328	char *path;                     /* разбираемый путь */
 26329	{
 26330	/* Разбор пути 'path' и помещение его индексного узла в таблицу индексных узлов. Если это 
 26331	 * невозможно,возврат значения NIL_INODE и запись кода ошибки в 'err_code'.
 26332	 */
 26333	
 26334	  register struct inode *ldip, *rip;
 26335	  char string[NAME_MAX];        /* хранит имя одного компонента пути */
 26336	
 26337	  /* Сначала открытие пути вплоть до последнего каталога. */
 26338	  if ( (ldip = last_dir(path, string)) == NIL_INODE) {
 26339	        return(NIL_INODE);      /* не удалось открыть последний каталог */
 26340	        }
 26341	
 26342	  /* Путь, состоящий толко из  "/" – особый случай. Проверить его. */
 26343	  if (string[0] == '\0') return(ldip);
 26344	
 26345	  /* Получение последнего компонента пути. */
 26346	  rip = advance(ldip, string);
 26347	  put_inode(ldip);
 26348	  return(rip);
 26349	}
	
 26351	/*===========================================================================*
 26352	 *                              last_dir                                     *
 26353	 *===========================================================================*/
 26354	PUBLIC struct inode *last_dir(path, string)
 26355	char *path;                     /* разбираемое имя */
 26356	char string[NAME_MAX];          /* сюда возвращается последний компонент */
 26357	{
 26358	/* Разбор пути 'path', находящегося в адресном пространстве файловой системы, до последнего
 26359	 * каталога, запись индексного узла последнего каталога в таблицу индексных узлов и возврат 
 26360	 * указателя на индексный узел. Кроме того, в переменную 'string' возвращается последний компонент 
 26361	 * пути. Если не удается открыть последний каталог, возврат NIL_INODE и причины ошибки в
 26362	 * переменной 'err_code'.
 26363	 *
 26364	 */
 26365	
 26366	  register struct inode *rip;
 26367	  register char *new_name;
 26368	  register struct inode *new_ip;
 26369	
 26370	  /* Абсолютный или относительный путь? Соответствующая инициализация 'rip'. */
 26371	  rip = (*path == '/' ? fp->fp_rootdir :  fp->fp_workdir);
 26372	
 26373	  /* Если каталог удален или путь пуст, возвращается ENOENT. */
 26374	  if (rip->i_nlinks == 0 || *path == '\0') {
 26375	        err_code = ENOENT;
 26376	        return(NIL_INODE);
 26377	  }
 26378	
 26379	  dup_inode(rip);               /* индексный узел возвращается в put_inode */
 26380	
 26381	  /* Покомпонентное сканирование пути. */
 26382	  while (TRUE) {
 26383	        /* Извлечение одного компонента. */
 26384	        if ( (new_name = get_name(path, string)) == (char*) 0) {
 26385	                put_inode(rip); /* некорректный путь в пространстве пользователя */
 26386	                return(NIL_INODE);
 26387	        }
 26388	        if (*new_name == '\0') {
 26389	                if ( (rip->i_mode & I_TYPE) == I_DIRECTORY) {
 26390	                        return(rip);    /* обычный выход */
 26391	                } else {
 26392	                        /* последний файл пути не является каталогом */
 26393	                        put_inode(rip);
 26394	                        err_code = ENOTDIR;                     
 26395	                        return(NIL_INODE);
 26396	                }
 26397	        }
 26398	
 26399	        /* Разбор пути не закончен. Продолжение. */
 26400	        new_ip = advance(rip, string);
 26401	        put_inode(rip);         /* неподходящее значение rip */
 26402	        if (new_ip == NIL_INODE) return(NIL_INODE);
 26403	
 26404	        /* Вызов advance() удачен. Получение следующего компонента. */
 26405	        path = new_name;
 26406	        rip = new_ip;
 26407	  }
 26408	}
	
 26410	/*===========================================================================*
 26411	 *                              get_name                                     *
 26412	 *===========================================================================*/
 26413	PRIVATE char *get_name(old_name, string)
 26414	char *old_name;                 /* разбираемое имя */
 26415	char string[NAME_MAX];          /* компонент, извлекаемый из 'old_name' */
 26416	{
 26417	/* Копирование следующего компонента 'string' и заполнение нулями по заданному указателю
 26418	 * на путь в пространстве файловой системы. Возвращается указатель на неразобранную часть
 26419	 * пути. Грубо говоря,
 26420	 * 'get_name' = 'old_name' - 'string'.
 26421	 *
 26422	 * Эта процедура следует стандартному соглашению о том, что пути /usr/ast, /usr//ast,
 26423	 * //usr///ast и /usr/ast/ эквивалентны.
 26424	 */
 26425	
 26426	  register int c;
 26427	  register char *np, *rnp;
 26428	
 26429	  np = string;                  /* 'np' указывает на текущую позицию */
 26430	  rnp = old_name;               /* 'rnp' указывает на неразобранную строку */
 26431	  while ( (c = *rnp) == '/') rnp++;     /* пропуск начальных слэшей */
 26432	
 26433	  /* Копирование неразобранного пути 'old_name' в массив 'string'. */
 26434	  while ( rnp < &old_name[PATH_MAX]  &&  c != '/'   &&  c != '\0') {
 26435	        if (np < &string[NAME_MAX]) *np++ = c;
 26436	        c = *++rnp;             /* переход к следующему символу */
 26437	  }
 26438	
 26439	  /* Чтобы пути /usr/ast/ и /usr/ast были эквивалентными, пропустить последний слэш. */
 26440	  while (c == '/' && rnp < &old_name[PATH_MAX]) c = *++rnp;
 26441	
 26442	  if (np < &string[NAME_MAX]) *np = '\0';       /* завершение строки */
 26443	
 26444	  if (rnp >= &old_name[PATH_MAX]) {
 26445	        err_code = ENAMETOOLONG;
 26446	        return((char *) 0);
 26447	  }
 26448	  return(rnp);
 26449	}
	
 26451	/*===========================================================================*
 26452	 *                              advance                                      *
 26453	 *===========================================================================*/
 26454	PUBLIC struct inode *advance(dirp, string)
 26455	struct inode *dirp;             /* индексный узел для каталога */
 26456	char string[NAME_MAX];          /* имя компонента для поиска */
 26457	{
 26458	/* Поиск компонента пути в заданном каталоге, открытие и возврат номера его индексного узла.
 26459	 * В случае неудачи возвращает NIL_INODE.
 26460	 *
 26461	 */
 26462	
 26463	  register struct inode *rip;
 26464	  struct inode *rip2;
 26465	  register struct super_block *sp;
 26466	  int r, inumb;
 26467	  dev_t mnt_dev;
 26468	  ino_t numb;
 26469	
 26470	  /* Если значение 'string' пусто, вернуть такой же индексный узел. */
 26471	  if (string[0] == '\0') { return(get_inode(dirp->i_dev, (int) dirp->i_num)); }
 26472	
 26473	  /* Проверка NIL_INODE. */
 26474	  if (dirp == NIL_INODE) { return(NIL_INODE); }
 26475	
 26476	  /* Если компонента 'string' нет в каталоге, вернуть ошибку. */
 26477	  if ( (r = search_dir(dirp, string, &numb, LOOK_UP)) != OK) {
 26478	        err_code = r;
 26479	        return(NIL_INODE);
 26480	  }
 26481	
 26482	  /* Не выходить за пределы текущего корневого каталога, если строка не dot2. */
 26483	  if (dirp == fp->fp_rootdir && strcmp(string, "..") == 0 && string != dot2)
 26484	                return(get_inode(dirp->i_dev, (int) dirp->i_num));
 26485	
 26486	  /* Компонент найден в каталоге. Получение индексного узла. */
 26487	  if ( (rip = get_inode(dirp->i_dev, (int) numb)) == NIL_INODE)  {
 26488	        return(NIL_INODE);
 26489	        }
 26490	
 26491	  if (rip->i_num == ROOT_INODE)
 26492	        if (dirp->i_num == ROOT_INODE) {
 26493	            if (string[1] == '.') {
 26494	                for (sp = &super_block[1]; sp < &super_block[NR_SUPERS]; sp++){
 26495	                        if (sp->s_dev == rip->i_dev) {
 26496	                                /* Освобождение корневого индексного узла. Замещение его
 26497	                                 * монтированным индексным узлом.
 26498	                                 */
 26499	                                put_inode(rip);
 26500	                                mnt_dev = sp->s_imount->i_dev;
 26501	                                inumb = (int) sp->s_imount->i_num;
 26502	                                rip2 = get_inode(mnt_dev, inumb);
 26503	                                rip = advance(rip2, string);
 26504	                                put_inode(rip2);
 26505	                                break;
 26506	                        }
 26507	                }
 26508	            }
 26509	        }
 26510	  if (rip == NIL_INODE) return(NIL_INODE);
 26511	
 26512	  /* Проверка, монтирован ли индексный узел. Если да, переход в корневой каталог монтированной
 26513	   * файловой системы. Суперблок связывает монтированный индексный узел и корневой каталог
 26514	   * монтированной файловой системы.
 26515	   */
 26516	  while (rip != NIL_INODE && rip->i_mount == I_MOUNT) {
 26517	        /* индексный узел действительно монтирован. */
 26518	        for (sp = &super_block[0]; sp < &super_block[NR_SUPERS]; sp++) {
 26519	                if (sp->s_imount == rip) {
 26520	                        /* Освобождение монтированного индексного узла. Замещение его
 26521	                         * корневым индексным узлом устройства.
 26522	                         */
 26523	                        put_inode(rip);
 26524	                        rip = get_inode(sp->s_dev, ROOT_INODE);
 26525	                        break;
 26526	                }
 26527	        }
 26528	  }
 26529	  return(rip);          /* возврат указателя на компонент индексного узла */
 26530	}
	
 26532	/*===========================================================================*
 26533	 *                              search_dir                                   *
 26534	 *===========================================================================*/
 26535	PUBLIC int search_dir(ldir_ptr, string, numb, flag)
 26536	register struct inode *ldir_ptr; /* указатель на индексный узел искомого каталога */
 26537	char string[NAME_MAX];           /* искомый компонент */
 26538	ino_t *numb;                     /* указатель на номер индексного узла */
 26539	int flag;                        /* LOOK_UP, ENTER, DELETE или IS_EMPTY */
 26540	{
 26541	/* Эта функция выполняет поиск каталога, на индексный узел которого указывает указатель 'ldip': 
 26542	 * if (flag == ENTER)  добавить 'string' в каталог с номером индексного узла '*numb';
 26543	 * if (flag == DELETE) удалить 'string' из каталога;
 26544	 * if (flag == LOOK_UP) поиск 'string' и возврат номера индексного узла в 'numb';
 26545	 * if (flag == IS_EMPTY) вернуть OK, если в каталоге имеются только записи . и .., иначе ENOTEMPTY;
 26546	 *
 26547	 *    если 'string' содержит . или .., разрешения не проверяются.
 26548	 */
 26549	
 26550	  register struct direct *dp = NULL;
 26551	  register struct buf *bp = NULL;
 26552	  int i, r, e_hit, t, match;
 26553	  mode_t bits;
 26554	  off_t pos;
 26555	  unsigned new_slots, old_slots;
 26556	  block_t b;
 26557	  struct super_block *sp;
 26558	  int extended = 0;
 26559	
 26560	  /* если 'ldir_ptr' не указатель на индексный узел каталога, ошибка. */
 26561	  if ( (ldir_ptr->i_mode & I_TYPE) != I_DIRECTORY) return(ENOTDIR);
 26562	
 26563	  r = OK;
 26564	
 26565	  if (flag != IS_EMPTY) {
 26566	        bits = (flag == LOOK_UP ? X_BIT :  W_BIT | X_BIT);
 26567	
 26568	        if (string == dot1 || string == dot2) {
 26569	                if (flag != LOOK_UP) r = read_only(ldir_ptr);
 26570	                                     /* нужно только устройство для записи. */
 26571	        }
 26572	        else r = forbidden(ldir_ptr, bits); /* проверка разрешений доступа */
 26573	  }
 26574	  if (r != OK) return(r);
 26575	  
 26576	  /* Поблочный проход по каталогу. */
 26577	  old_slots = (unsigned) (ldir_ptr->i_size/DIR_ENTRY_SIZE);
 26578	  new_slots = 0;
 26579	  e_hit = FALSE;
 26580	  match = 0;                    /* устанавливается, когда найдено соответствие */
 26581	
 26582	  for (pos = 0; pos < ldir_ptr->i_size; pos += ldir_ptr->i_sp->s_block_size) {
 26583	        b = read_map(ldir_ptr, pos);    /* получение номера блока */
 26584	
 26585	        /* Поскольку в каталогах не бывает дыр, 'b' не может быть NO_BLOCK. */
 26586	        bp = get_block(ldir_ptr->i_dev, b, NORMAL);     /* получение блока каталога */
 26587	
 26588	        if (bp == NO_BLOCK)
 26589	                panic(__FILE__,"get_block returned NO_BLOCK", NO_NUM);
 26590	
 26591	        /* Поиск блока каталога. */
 26592	        for (dp = &bp->b_dir[0];
 26593	                dp < &bp->b_dir[NR_DIR_ENTRIES(ldir_ptr->i_sp->s_block_size)];
 26594	                dp++) {
 26595	                if (++new_slots > old_slots) { /* не найден, но место осталось */
 26596	                        if (flag == ENTER) e_hit = TRUE;
 26597	                        break;
 26598	                }
 26599	
 26600	                /* Совпадение происходит, если строка найдена. */
 26601	                if (flag != ENTER && dp->d_ino != 0) {
 26602	                        if (flag == IS_EMPTY) {
 26603	                                /* Если проверка успешна, каталог не пуст. */
 26604	                                if (strcmp(dp->d_name, "." ) != 0 &&
 26605	                                    strcmp(dp->d_name, "..") != 0) match = 1;
 26606	                        } else {
 26607	                                if (strncmp(dp->d_name, string, NAME_MAX) == 0) {
 26608	                                        match = 1;
 26609	                                }
 26610	                        }
 26611	                }
 26612	
 26613	                if (match) {
 26614	                        /* LOOK_UP или DELETE найдено то, что нужно. */
 26615	                        r = OK;
 26616	                        if (flag == IS_EMPTY) r = ENOTEMPTY;
 26617	                        else if (flag == DELETE) {
 26618	                                /* Сохранение d_ino для восстановления. */
 26619	                                t = NAME_MAX - sizeof(ino_t);
 26620	                                *((ino_t *) &dp->d_name[t]) = dp->d_ino;
 26621	                                dp->d_ino = 0;  /* удаление записи */
 26622	                                bp->b_dirt = DIRTY;
 26623	                                ldir_ptr->i_update |= CTIME | MTIME;
 26624	                                ldir_ptr->i_dirt = DIRTY;
 26625	                        } else {
 26626	                                sp = ldir_ptr->i_sp;    /* 'flag' = LOOK_UP */
 26627	                                *numb = conv4(sp->s_native, (int) dp->d_ino);
 26628	                        }
 26629	                        put_block(bp, DIRECTORY_BLOCK);
 26630	                        return(r);
 26631	                }
 26632	
 26633	                /* Проверка наличия свободной записи для ENTER. */
 26634	                if (flag == ENTER && dp->d_ino == 0) {
 26635	                        e_hit = TRUE;   /* свободная запись найдена */
 26636	                        break;
 26637	                }
 26638	        }
 26639	
 26640	        /* Выполнен поиск во всем блоке или ENTER найдена свободная запись. */
 26641	        if (e_hit) break;       /* e_hit устанавливается, если ENTER можно выполнить сейчас */
 26642	        put_block(bp, DIRECTORY_BLOCK); /* в противном случае продолжение поиска в каталоге */
 26643	  }
 26644	
 26645	  /* Поиск в каталоге завершен. */
 26646	  if (flag != ENTER) {
 26647	        return(flag == IS_EMPTY ? OK :  ENOENT);
 26648	  }
 26649	
 26650	  /* Вызов для ENTER. Если к этому моменту не удалось найти свободную запись, расширение
 26651	   * каталога.
 26652	   */
 26653	  if (e_hit == FALSE) { /* каталог полон и в последнем блоке не осталось места */
 26654	        new_slots++;            /* увеличение размера каталога на 1 запись */
 26655	        if (new_slots == 0) return(EFBIG); /* размер каталога ограничен числом записей */
 26656	        if ( (bp = new_block(ldir_ptr, ldir_ptr->i_size)) == NIL_BUF)
 26657	                return(err_code);
 26658	        dp = &bp->b_dir[0];
 26659	        extended = 1;
 26660	  }
 26661	
 26662	  /* теперь 'bp' указывает на блок каталога со свободным местом, а 'dp' - на запись. */
 26663	  (void) memset(dp->d_name, 0, (size_t) NAME_MAX); /* очистка записи */
 26664	  for (i = 0; string[i] && i < NAME_MAX; i++) dp->d_name[i] = string[i];
 26665	  sp = ldir_ptr->i_sp; 
 26666	  dp->d_ino = conv4(sp->s_native, (int) *numb);
 26667	  bp->b_dirt = DIRTY;
 26668	  put_block(bp, DIRECTORY_BLOCK);
 26669	  ldir_ptr->i_update |= CTIME | MTIME;  /* пометка mtime для обновления в будущем */
 26670	  ldir_ptr->i_dirt = DIRTY;
 26671	  if (new_slots > old_slots) {
 26672	        ldir_ptr->i_size = (off_t) new_slots * DIR_ENTRY_SIZE;
 26673	        /* Если каталог расширился, отправка изменений на диск. */
 26674	        if (extended) rw_inode(ldir_ptr, WRITING);
 26675	  }
 26676	  return(OK);
 26677	}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/mount.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 26700	/* Этот файл выполняет системные вызовы MOUNT и UMOUNT.
 26701	 *
 26702	 * Файл имеет следующие точки входа
 26703	 *   do_mount:   выполнение системного вызова MOUNT
 26704	 *   do_umount:  выполнение системного вызова UMOUNT
 26705	 */
 26706	
 26707	#include "fs.h"
 26708	#include <fcntl.h>
 26709	#include <minix/com.h>
 26710	#include <sys/stat.h>
 26711	#include "buf.h"
 26712	#include "file.h"
 26713	#include "fproc.h"
 26714	#include "inode.h"
 26715	#include "param.h"
 26716	#include "super.h"
 26717	
 26718	FORWARD _PROTOTYPE( dev_t name_to_dev, (char *path)                     );
 26719	
 26720	/*===========================================================================*
 26721	 *                              do_mount                                     *
 26722	 *===========================================================================*/
 26723	PUBLIC int do_mount()
 26724	{
 26725	/* выполнение системного вызова mount(name, mfile, rd_only). */
 26726	
 26727	  register struct inode *rip, *root_ip;
 26728	  struct super_block *xp, *sp;
 26729	  dev_t dev;
 26730	  mode_t bits;
 26731	  int rdir, mdir;               /* TRUE, если корневой и/или монтируемый файл является каталогом  */
 26732	  int r, found;
 26733	
 26734	  /* Только суперпользователь может выполнять системный вызов MOUNT. */
 26735	  if (!super_user) return(EPERM);
 26736	
 26737	  /* Если 'name' не является блочным специальным файлом, возвращается ошибка. */
 26738	  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
 26739	  if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code);
 26740	
 26741	  /* Сканирование таблицы суперблоков для выяснения, смонтировано ли устройство, и поиск свободной записи.*/
 26742	  sp = NIL_SUPER;
 26743	  found = FALSE;
 26744	  for (xp = &super_block[0]; xp < &super_block[NR_SUPERS]; xp++) {
 26745	        if (xp->s_dev == dev) found = TRUE;     /* смонтировано ли устройство? */
 26746	        if (xp->s_dev == NO_DEV) sp = xp;       /* свободная запись */
 26747	  }
 26748	  if (found) return(EBUSY);     /* уже смонтировано */
 26749	  if (sp == NIL_SUPER) return(ENFILE);  /* нет доступного суперблока */
 26750	
 26751	  /* Открытие устройства, на котором расположена файловая система. */
 26752	  if (dev_open(dev, who, m_in.rd_only ? R_BIT :  (R_BIT|W_BIT)) != OK) 
 26753	        return(EINVAL);
 26754	
 26755	  /* Объявление недействительными блоков кэша, открытых на файловой системе */
 26756	  (void) do_sync();
 26757	  invalidate(dev);
 26758	
 26759	  /* Заполнение суперблока. */
 26760	  sp->s_dev = dev;              /* read_super() нужно знать устройство */
 26761	  r = read_super(sp);
 26762	
 26763	  /* является ли файловая система файловой системой Minix? */
 26764	  if (r != OK) {
 26765	        dev_close(dev);
 26766	        sp->s_dev = NO_DEV;
 26767	        return(r);
 26768	  }
 26769	
 26770	  /* Получение индексного узла файла для монтирования. */
 26771	  if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) {
 26772	        dev_close(dev);
 26773	        sp->s_dev = NO_DEV;
 26774	        return(err_code);
 26775	  }
 26776	  if ( (rip = eat_path(user_path)) == NIL_INODE) {
 26777	        dev_close(dev);
 26778	        sp->s_dev = NO_DEV;
 26779	        return(err_code);
 26780	  }
 26781	
 26782	  /* Файл не может быть занят. */
 26783	  r = OK;
 26784	  if (rip->i_count > 1) r = EBUSY;
 26785	
 26786	  /* Файл не может быть специальным. */
 26787	  bits = rip->i_mode & I_TYPE;
 26788	  if (bits == I_BLOCK_SPECIAL || bits == I_CHAR_SPECIAL) r = ENOTDIR;
 26789	
 26790	  /* Получение корневого индексного узла монтированной файловой системы. */
 26791	  root_ip = NIL_INODE;          /* если 'r' не равно OK, задать значение */
 26792	  if (r == OK) {
 26793	        if ( (root_ip = get_inode(dev, ROOT_INODE)) == NIL_INODE) r = err_code;
 26794	  }
 26795	  if (root_ip != NIL_INODE && root_ip->i_mode == 0) {
 26796	        r = EINVAL;
 26797	  }
 26798	
 26799	  /* Типы файлов 'rip' и 'root_ip' не могут конфликтовать. */
 26800	  if (r == OK) {
 26801	        mdir = ((rip->i_mode & I_TYPE) == I_DIRECTORY);  /* TRUE, если каталог */
 26802	        rdir = ((root_ip->i_mode & I_TYPE) == I_DIRECTORY);
 26803	        if (!mdir && rdir) r = EISDIR;
 26804	  }
 26805	
 26806	  /* В случае ошибки возврат суперблока и обоих индексных узлов; освобождение карт. */
 26807	  if (r != OK) {
 26808	        put_inode(rip);
 26809	        put_inode(root_ip);
 26810	        (void) do_sync();
 26811	        invalidate(dev);
 26812	        dev_close(dev);
 26813	        sp->s_dev = NO_DEV;
 26814	        return(r);
 26815	  }
 26816	
 26817	  /* Других проблем быть не может. Выполнение монтирования. */
 26818	  rip->i_mount = I_MOUNT;       /* этот бит указывает, что индексный узел монтирован */
 26819	  sp->s_imount = rip;
 26820	  sp->s_isup = root_ip;
 26821	  sp->s_rd_only = m_in.rd_only;
 26822	  return(OK);
 26823	}
	
 26825	/*===========================================================================*
 26826	 *                              do_umount                                    *
 26827	 *===========================================================================*/
 26828	PUBLIC int do_umount()
 26829	{
 26830	/* выполнение системного вызова umount(name). */
 26831	  dev_t dev;
 26832	
 26833	  /* Только суперпользователь может выполнять UMOUNT. */
 26834	  if (!super_user) return(EPERM);
 26835	
 26836	  /* Если 'name' не является блочным специальным файлом, возвращается ошибка. */
 26837	  if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
 26838	  if ( (dev = name_to_dev(user_path)) == NO_DEV) return(err_code);
 26839	
 26840	  return(unmount(dev));
 26841	}
	
 26843	/*===========================================================================*
 26844	 *                              unmount                                      *
 26845	 *===========================================================================*/
 26846	PUBLIC int unmount(dev)
 26847	Dev_t dev;
 26848	{
 26849	/* Демонтирование файловой системы по номеру устройства. */
 26850	  register struct inode *rip;
 26851	  struct super_block *sp, *sp1;
 26852	  int count;
 26853	
 26854	  /* Проверка, занято ли монтированное устройство. На нем должен быть открыть только один,
 26855	   * корневой, индексный узел, и всего один раз.
 26856	   */
 26857	  count = 0;
 26858	  for (rip = &inode[0]; rip< &inode[NR_INODES]; rip++)
 26859	        if (rip->i_count > 0 && rip->i_dev == dev) count += rip->i_count;
 26860	  if (count > 1) return(EBUSY); /* can't umount a busy file system */
 26861	
 26862	  /* Поиск суперблока. */
 26863	  sp = NIL_SUPER;
 26864	  for (sp1 = &super_block[0]; sp1 < &super_block[NR_SUPERS]; sp1++) {
 26865	        if (sp1->s_dev == dev) {
 26866	                sp = sp1;
 26867	                break;
 26868	        }
 26869	  }
 26870	
 26871	  /* Синхронизация диска и объявление кэша недействительным. */
 26872	  (void) do_sync();             /* вытеснение из памяти всех кэшированных блоков */
 26873	  invalidate(dev);              /* объявление недействительными всех записей кэша для этого устройства */
 26874	  if (sp == NIL_SUPER) {
 26875	        return(EINVAL);
 26876	  }
 26877	
 26878	  /* Закрыть устройство, на котором расположена файловая система. */
 26879	  dev_close(dev);
 26880	
 26881	  /* Завершение демонтирования. */
 26882	  sp->s_imount->i_mount = NO_MOUNT;     /* индексный узел становится обычным */
 26883	  put_inode(sp->s_imount);      /* освобождение монтированного индексного узла */
 26884	  put_inode(sp->s_isup);        /* освобождение корневого индексного узла монтированной файловой системы */
 26885	  sp->s_imount = NIL_INODE;
 26886	  sp->s_dev = NO_DEV;
 26887	  return(OK);
 26888	}
	
 26890	/*===========================================================================*
 26891	 *                              name_to_dev                                  *
 26892	 *===========================================================================*/
 26893	PRIVATE dev_t name_to_dev(path)
 26894	char *path;                     /* указатель на путь */
 26895	{
 26896	/* Преобразование блочного специального файла 'path' в номер устройства. Если 'path' не
 26897	 * является блочным специальным файлом, возврат кода ошибки в 'err_code'.
 26898	 */
 26899	
 26900	  register struct inode *rip;
 26901	  register dev_t dev;
 26902	
 26903	  /* Если путь 'path' невозможно открыть, немедленное завершение. */
 26904	  if ( (rip = eat_path(path)) == NIL_INODE) return(NO_DEV);
 26905	
 26906	  /* Если 'path' не является блочным специальным файлом, возврат ошибки. */
 26907	  if ( (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) {
 26908	        err_code = ENOTBLK;
 26909	        put_inode(rip);
 26910	        return(NO_DEV);
 26911	  }
 26912	
 26913	  /* Извлечение номера устройства. */
 26914	  dev = (dev_t) rip->i_zone[0];
 26915	  put_inode(rip);
 26916	  return(dev);
 26917	}



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/link.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 27000	/* Этот файл обрабатывает системные вызовы LINK и UNLINK. Он также освобождает память,
 27001	 * используемую файлом, когда уничтожается последняя связь файла и блоки необходимо
 27002	 * вернуть в пул свободных блоков.
 27003	 *
 27004	 * Файл имеет следующие точки входа
 27005	 *   do_link:    выполнение системного вызова LINK
 27006	 *   do_unlink:  выполнение системного вызова UNLINK и RMDIR
 27007	 *   do_rename:  выполнение системного вызова RENAME
 27008	 *   truncate:   освобождение всех блоков, связанных с индексным узлом
 27009	 */
 27010	
 27011	#include "fs.h"
 27012	#include <sys/stat.h>
 27013	#include <string.h>
 27014	#include <minix/com.h>
 27015	#include <minix/callnr.h>
 27016	#include "buf.h"
 27017	#include "file.h"
 27018	#include "fproc.h"
 27019	#include "inode.h"
 27020	#include "param.h"
 27021	#include "super.h"
 27022	
 27023	#define SAME 1000
 27024	
 27025	FORWARD _PROTOTYPE( int remove_dir, (struct inode *rldirp, struct inode *rip,
 27026	                        char dir_name[NAME_MAX])                        );
 27027	
 27028	FORWARD _PROTOTYPE( int unlink_file, (struct inode *dirp, struct inode *rip,
 27029	                        char file_name[NAME_MAX])                       );
 27030	
 27031	/*===========================================================================*
 27032	 *                              do_link                                      *
 27033	 *===========================================================================*/
 27034	PUBLIC int do_link()
 27035	{
 27036	/* Выполнение системного вызова link(name1, name2). */
 27037	
 27038	  register struct inode *ip, *rip;
 27039	  register int r;
 27040	  char string[NAME_MAX];
 27041	  struct inode *new_ip;
 27042	
 27043	  /* Проверка существования файла с именем 'name'. */
 27044	  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
 27045	  if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
 27046	
 27047	  /* Проверка наличия у файла максимально возможного числа связей. */
 27048	  r = OK;
 27049	  if (rip->i_nlinks >= (rip->i_sp->s_version == V1 ? CHAR_MAX :  SHRT_MAX))
 27050	        r = EMLINK;
 27051	
 27052	  /* Только суперпользователь может создавать связи для каталогов. */
 27053	  if (r == OK)
 27054	        if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM;
 27055	
 27056	  /* Если ошибка с 'name', возврат индексного узла. */
 27057	  if (r != OK) {
 27058	        put_inode(rip);
 27059	        return(r);
 27060	  }
 27061	
 27062	  /* Существует ли конечный каталог 'name2'? */
 27063	  if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) {
 27064	        put_inode(rip);
 27065	        return(err_code);
 27066	  }
 27067	  if ( (ip = last_dir(user_path, string)) == NIL_INODE) r = err_code;
 27068	
 27069	  /* Если 'name2' существует, то установить в r ошибку, даже если каталог полон. */
 27070	  if (r == OK) {
 27071	        if ( (new_ip = advance(ip, string)) == NIL_INODE) {
 27072	                r = err_code;
 27073	                if (r == ENOENT) r = OK;
 27074	        } else {
 27075	                put_inode(new_ip);
 27076	                r = EEXIST;
 27077	        }
 27078	  }
 27079	
 27080	  /* Проверка связей на устройствах. */
 27081	  if (r == OK)
 27082	        if (rip->i_dev != ip->i_dev) r = EXDEV;
 27083	
 27084	  /* Попытка создания связи. */
 27085	  if (r == OK)
 27086	        r = search_dir(ip, string, &rip->i_num, ENTER);
 27087	
 27088	  /* В случае успеха регистрация связи. */
 27089	  if (r == OK) {
 27090	        rip->i_nlinks++;
 27091	        rip->i_update |= CTIME;
 27092	        rip->i_dirt = DIRTY;
 27093	  }
 27094	
 27095	  /* Вызов завершен. Освобождение обоих индексных узлов. */
 27096	  put_inode(rip);
 27097	  put_inode(ip);
 27098	  return(r);
 27099	}
	
 27101	/*===========================================================================*
 27102	 *                              do_unlink                                    *
 27103	 *===========================================================================*/
 27104	PUBLIC int do_unlink()
 27105	{
 27106	/* Выполнение системного вызова unlink(name) или rmdir(name). Их коды почти совпадают.
 27107	 * Различия заключаются лишь в проверяемых условиях. Суперпользователь может задействовать
 27108	 * unlink() для опасных действий, которые не может выполнить rmdir().
 27109	 */
 27110	
 27111	  register struct inode *rip;
 27112	  struct inode *rldirp;
 27113	  int r;
 27114	  char string[NAME_MAX];
 27115	
 27116	  /* Получение последнего каталога пути. */
 27117	  if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
 27118	  if ( (rldirp = last_dir(user_path, string)) == NIL_INODE)
 27119	        return(err_code);
 27120	
 27121	  /* Последний каталог существует. Существует ли также и файл? */
 27122	  r = OK;
 27123	  if ( (rip = advance(rldirp, string)) == NIL_INODE) r = err_code;
 27124	
 27125	  /* В случае ошибки возвращается индексный узел. */
 27126	  if (r != OK) {
 27127	        put_inode(rldirp);
 27128	        return(r);
 27129	  }
 27130	
 27131	  /* Не удаляем точку монтирования. */
 27132	  if (rip->i_num == ROOT_INODE) {
 27133	        put_inode(rldirp);
 27134	        put_inode(rip);
 27135	        return(EBUSY);
 27136	  }
 27137	
 27138	  /* Проверка разрешения на вызов – отдельная для unlink() rmdir(). */
 27139	  if (call_nr == UNLINK) {
 27140	        /* Только суперпользователь может удалять связи для каталогов, но он может делать это для любых каталогов.*/
 27141	        if ( (rip->i_mode & I_TYPE) == I_DIRECTORY && !super_user) r = EPERM;
 27142	
 27143	        /* Не удалять связь файла, если он является корневым для монтированной файловой системы. */
 27144	        if (rip->i_num == ROOT_INODE) r = EBUSY;
 27145	
 27146	        /* Фактическая попытка удаления связи. Заканчивается неудачно, если родительский каталог в режиме 0 и т. д. */
 27147	        if (r == OK) r = unlink_file(rldirp, rip, string);
 27148	
 27149	  } else {
 27150	        r = remove_dir(rldirp, rip, string); /* RMDIR */
 27151	  }
 27152	
 27153	  /* Если удаление связи оказалось возможным, оно завершилось успешно, в противном случае нет. */
 27154	  put_inode(rip);
 27155	  put_inode(rldirp);
 27156	  return(r);
 27157	}
	
 27159	/*===========================================================================*
 27160	 *                              do_rename                                    *
 27161	 *===========================================================================*/
 27162	PUBLIC int do_rename()
 27163	{
 27164	/* Выполнение системного вызова rename(name1, name2). */
 27165	
 27166	  struct inode *old_dirp, *old_ip;      /* указатели на старый каталог и индексные узлы файлов */
 27167	  struct inode *new_dirp, *new_ip;      /* указатели на новый каталог и  индексные узлы файлов */
 27168	  struct inode *new_superdirp, *next_new_superdirp;
 27169	  int r = OK;                           /* флаг ошибки; изначально не установлен */
 27170	  int odir, ndir;                       /* TRUE, если старый и/или новый файл является каталогом */
 27171	  int same_pdir;                        /* TRUE, если родительские каталоги одинаковы */
 27172	  char old_name[NAME_MAX], new_name[NAME_MAX];
 27173	  ino_t numb;
 27174	  int r1;
 27175	  
 27176	  /* Проверка существования файла 'name1' (существующего), получение каталога и индексных узлов. */
 27177	  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
 27178	  if ( (old_dirp = last_dir(user_path, old_name))==NIL_INODE) return(err_code);
 27179	
 27180	  if ( (old_ip = advance(old_dirp, old_name)) == NIL_INODE) r = err_code;
 27181	
 27182	  /* Проверка существования файла 'name2' (нового), получение каталога и индексных узлов.*/
 27183	  if (fetch_name(m_in.name2, m_in.name2_length, M1) != OK) r = err_code;
 27184	  if ( (new_dirp = last_dir(user_path, new_name)) == NIL_INODE) r = err_code;
 27185	  new_ip = advance(new_dirp, new_name); /* существование не обязательно */
 27186	
 27187	  if (old_ip != NIL_INODE)
 27188	        odir = ((old_ip->i_mode & I_TYPE) == I_DIRECTORY);  /* TRUE, если каталог */
 27189	
 27190	  /* Если ok, то проверка на возможные ошибки. */
 27191	  if (r == OK) {
 27192	        same_pdir = (old_dirp == new_dirp);
 27193	
 27194	        /* Старый индексный узел не должен быть предком нового каталога. */
 27195	        if (odir && !same_pdir) {
 27196	                dup_inode(new_superdirp = new_dirp);
 27197	                while (TRUE) {          /* возможно зависание в цикле файловой системы*/
 27198	                        if (new_superdirp == old_ip) {
 27199	                                r = EINVAL;
 27200	                                break;
 27201	                        }
 27202	                        next_new_superdirp = advance(new_superdirp, dot2);
 27203	                        put_inode(new_superdirp);
 27204	                        if (next_new_superdirp == new_superdirp)
 27205	                                break;  /* возврат в корневой каталог системы */
 27206	                        new_superdirp = next_new_superdirp;
 27207	                        if (new_superdirp == NIL_INODE) {
 27208	                                /* Запись ".." отсутствует.  Предполагаем худшее. */
 27209	                                r = EINVAL;
 27210	                                break;
 27211	                        }
 27212	                }       
 27213	                put_inode(new_superdirp);
 27214	        }       
 27215	
 27216	        /* Старое и новое имя должны отличаться от . и .. */
 27217	        if (strcmp(old_name, ".")==0 || strcmp(old_name, "..")==0 ||
 27218	            strcmp(new_name, ".")==0 || strcmp(new_name, "..")==0) r = EINVAL;
 27219	
 27220	        /* Оба родительских каталога должны располагаться на одном устройстве. */
 27221	        if (old_dirp->i_dev != new_dirp->i_dev) r = EXDEV;
 27222	
 27223	        /* Родительские каталоги должны иметь разрешение на запись и поиск и находиться на устройстве для записи */
 27224	        if ((r1 = forbidden(old_dirp, W_BIT | X_BIT)) != OK ||
 27225	            (r1 = forbidden(new_dirp, W_BIT | X_BIT)) != OK) r = r1;
 27226	
 27227	        /* Несколько проверок для случая, если новый путь существует. */
 27228	        if (new_ip == NIL_INODE) {
 27229	                /* не переименовывать файл, если к нему монтирована файловая система. */
 27230	                if (old_ip->i_dev != old_dirp->i_dev) r = EXDEV;
 27231	                if (odir && new_dirp->i_nlinks >=
 27232	                    (new_dirp->i_sp->s_version == V1 ? CHAR_MAX :  SHRT_MAX) &&
 27233	                    !same_pdir && r == OK) r = EMLINK;
 27234	        } else {
 27235	                if (old_ip == new_ip) r = SAME; /* старый=новый */
 27236	
 27237	                /* монтирована ли файловая система к старому или новому файлу? */
 27238	                if (old_ip->i_dev != new_ip->i_dev) r = EXDEV;
 27239	
 27240	                ndir = ((new_ip->i_mode & I_TYPE) == I_DIRECTORY); /* каталог ? */
 27241	                if (odir == TRUE && ndir == FALSE) r = ENOTDIR;
 27242	                if (odir == FALSE && ndir == TRUE) r = EISDIR;
 27243	        }
 27244	  }
 27245	
 27246	  /* Если у процесса есть еще один корневой каталог, отличный от системного, мы можем
 27247	   * "случайно" переместить его рабочий каталог туда, где корневой каталог не является
 27248	   * для него предком. Это может сделать функцию chroot бесполезной. Если chroot будет
 27249	   * использоваться часто, нам следует провести здесь проверку.
 27250	   *
 27251	   */
 27252	
 27253	  /* Переименование, по всей вероятности, сработает. Могут возникнуть лишь две проблемы:
 27254	   * 1. удалить новый файл невозможно (если новый файл уже существует)
 27255	   * 2. невозможно создать новую запись каталога (новый файл не существует)
 27256	   *     [каталог нужно расширить на один блок, но это невозможно из-за того, что диск
 27257	   *      полон].
 27258	   */
 27259	  if (r == OK) {
 27260	        if (new_ip != NIL_INODE) {
 27261	                  /* Запись для 'new' уже существует. Удалить ее. */
 27262	                if (odir) 
 27263	                        r = remove_dir(new_dirp, new_ip, new_name);
 27264	                else 
 27265	                        r = unlink_file(new_dirp, new_ip, new_name);
 27266	        }
 27267	        /* Если r == OK, переименование будет успешным, поскольку теперь имеется неиспользованная
 27268	         * запись в новом родительском каталоге.
 27269	         */
 27270	  }
 27271	
 27272	  if (r == OK) {
 27273	        /* Если новое имя будет в том же родительском каталогое, что и старое, сначала
 27274	         * удаление старого имени, чтобы освободить запись под новое имя, в противном
 27275	         * случае создание новой записи для нового имени
 27276	         *
 27277	         */
 27278	        numb = old_ip->i_num;           /* номер индексного узла старого файла */
 27279	
 27280	        if (same_pdir) {
 27281	                r = search_dir(old_dirp, old_name, (ino_t *) 0, DELETE);
 27282	                                                /* проблем быть не должно */
 27283	                if (r==OK) (void) search_dir(old_dirp, new_name, &numb, ENTER);
 27284	        } else {
 27285	                r = search_dir(new_dirp, new_name, &numb, ENTER);
 27286	                if (r == OK)
 27287	                    (void) search_dir(old_dirp, old_name, (ino_t *) 0, DELETE);
 27288	        }
 27289	  }
 27290	  /* Если r == OK, значения ctime и mtime каталогов old_dirp и new_dirp помечены для
 27291	   * обновления в search_dir.
 27292	   */
 27293	
 27294	  if (r == OK && odir && !same_pdir) {
 27295	        /* Обновление записи .. в каталоге (она все еще указывает на old_dirp). */
 27296	        numb = new_dirp->i_num;
 27297	        (void) unlink_file(old_ip, NIL_INODE, dot2);
 27298	        if (search_dir(old_ip, dot2, &numb, ENTER) == OK) {
 27299	                /* New link created. */
 27300	                new_dirp->i_nlinks++;
 27301	                new_dirp->i_dirt = DIRTY;
 27302	        }
 27303	  }
 27304	        
 27305	  /* Освобождение индексных узлов. */
 27306	  put_inode(old_dirp);
 27307	  put_inode(old_ip);
 27308	  put_inode(new_dirp);
 27309	  put_inode(new_ip);
 27310	  return(r == SAME ? OK :  r);
 27311	}
	
 27313	/*===========================================================================*
 27314	 *                              truncate                                     *
 27315	 *===========================================================================*/
 27316	PUBLIC void truncate(rip)
 27317	register struct inode *rip;     /* указатель на отбрасываемый индексный узел */
 27318	{
 27319	/* Удаление всех зон из индексного узла 'rip' и пометка его как измененного. */
 27320	
 27321	  register block_t b;
 27322	  zone_t z, zone_size, z1;
 27323	  off_t position;
 27324	  int i, scale, file_type, waspipe, single, nr_indirects;
 27325	  struct buf *bp;
 27326	  dev_t dev;
 27327	
 27328	  file_type = rip->i_mode & I_TYPE;     /* проверка, является ли файл специальным */
 27329	  if (file_type == I_CHAR_SPECIAL || file_type == I_BLOCK_SPECIAL) return;
 27330	  dev = rip->i_dev;             /* устройство, на котором расположен индексный узел */
 27331	  scale = rip->i_sp->s_log_zone_size;
 27332	  zone_size = (zone_t) rip->i_sp->s_block_size << scale;
 27333	  nr_indirects = rip->i_nindirs;
 27334	
 27335	  /* Каналы могут сокращаться, поэтому изменяем размер так, чтобы все зоны оказались удалены. */
 27336	  waspipe = rip->i_pipe == I_PIPE;      /* TRUE, если это был канал */
 27337	  if (waspipe) rip->i_size = PIPE_SIZE(rip->i_sp->s_block_size);
 27338	
 27339	  /* Проход по зонам файла - их обнаружение и освобождение. */
 27340	  for (position = 0; position < rip->i_size; position += zone_size) {
 27341	        if ( (b = read_map(rip, position)) != NO_BLOCK) {
 27342	                z = (zone_t) b >> scale;
 27343	                free_zone(dev, z);
 27344	        }
 27345	  }
 27346	
 27347	  /* Все зоны данных освобождены. Освобождение косвенных зон. */
 27348	  rip->i_dirt = DIRTY;
 27349	  if (waspipe) {
 27350	        wipe_inode(rip);        /* очистка индексных узлов для каналов */
 27351	        return;                 /* косвенные записи содержат позиции файлов */
 27352	  }
 27353	  single = rip->i_ndzones;
 27354	  free_zone(dev, rip->i_zone[single]);  /* косвенная зона */
 27355	  if ( (z = rip->i_zone[single+1]) != NO_ZONE) {
 27356	        /* Освобождение всех косвенных зон, на которые указывают дважды косвенные зоны. */
 27357	        b = (block_t) z << scale;
 27358	        bp = get_block(dev, b, NORMAL); /* получение дважды косвенной зоны */
 27359	        for (i = 0; i < nr_indirects; i++) {
 27360	                z1 = rd_indir(bp, i);
 27361	                free_zone(dev, z1);
 27362	        }
 27363	
 27364	        /* освобождение самой дважды косвенной зоны. */
 27365	        put_block(bp, INDIRECT_BLOCK);
 27366	        free_zone(dev, z);
 27367	  }
 27368	
 27369	  /* Номера зон остаются для de(1), чтобы восстановить файл после unlink(2).  */
 27370	}
	
 27372	/*===========================================================================*
 27373	 *                              remove_dir                                   *
 27374	 *===========================================================================*/
 27375	PRIVATE int remove_dir(rldirp, rip, dir_name)
 27376	struct inode *rldirp;                   /* родительский каталог */
 27377	struct inode *rip;                      /* удаляемый каталог */
 27378	char dir_name[NAME_MAX];                /* имя удаляемого каталога */
 27379	{
 27380	  /* Для удаления файла каталога требуется соблюдение пяти условий: 
 27381	   *    - файл должен являться каталогом
 27382	   *    - каталог должен быть пустым (содержать только каталоги . и ..)
 27383	   *    - последний компонент пути не должен быть . или ..
 27384	   *    - каталог не должен быть корневым каталогом монтированной файловой системы
 27385	   *    - каталог не должен являться чьим-либо корневым/рабочим каталогом
 27386	   */
 27387	
 27388	  int r;
 27389	  register struct fproc *rfp;
 27390	
 27391	  /* search_dir проверяет, что rip – также каталог. */
 27392	  if ((r = search_dir(rip, "", (ino_t *) 0, IS_EMPTY)) != OK) return r;
 27393	
 27394	  if (strcmp(dir_name, ".") == 0 || strcmp(dir_name, "..") == 0)return(EINVAL);
 27395	  if (rip->i_num == ROOT_INODE) return(EBUSY); /* невозможно удалить'root' */
 27396	  
 27397	  for (rfp = &fproc[INIT_PROC_NR + 1]; rfp < &fproc[NR_PROCS]; rfp++)
 27398	        if (rfp->fp_workdir == rip || rfp->fp_rootdir == rip) return(EBUSY);
 27399	                                /* невозможно удалить рабочий каталог */
 27400	
 27401	  /* Попытка фактически удалить файл; если родительский каталог в режиме 0 и т. п., она закончится неудачей */
 27402	  if ((r = unlink_file(rldirp, rip, dir_name)) != OK) return r;
 27403	
 27404	  /* Удаление связей . и .. из каталога. Суперпользователь может создавать и удалять связи 
 27405	   * любых каталогов, поэтому не следует излишне полагаться на них.
 27406	   */
 27407	  (void) unlink_file(rip, NIL_INODE, dot1);
 27408	  (void) unlink_file(rip, NIL_INODE, dot2);
 27409	  return(OK);
 27410	}
	
 27412	/*===========================================================================*
 27413	 *                              unlink_file                                  *
 27414	 *===========================================================================*/
 27415	PRIVATE int unlink_file(dirp, rip, file_name)
 27416	struct inode *dirp;             /* родительский каталог файла */
 27417	struct inode *rip;              /* индексный узел файла, возможно тоже NIL_INODE. */
 27418	char file_name[NAME_MAX];       /* имая удаляемого файла */
 27419	{
 27420	/* Удаление связи 'file_name'; rip должен быть индексным узлом 'file_name' или NIL_INODE. */
 27421	
 27422	  ino_t numb;                   /* номер индексного узла */
 27423	  int   r;
 27424	
 27425	  /* Если rip - не NIL_INODE, он используется для ускоренного доступа к индексному узлу. */
 27426	  if (rip == NIL_INODE) {
 27427	        /* Поиск файла в каталоге и попытка получить его индексный узел. */
 27428	        err_code = search_dir(dirp, file_name, &numb, LOOK_UP);
 27429	        if (err_code == OK) rip = get_inode(dirp->i_dev, (int) numb);
 27430	        if (err_code != OK || rip == NIL_INODE) return(err_code);
 27431	  } else {
 27432	        dup_inode(rip);         /* индексный узел будет возвращен put_inode */
 27433	  }
 27434	
 27435	  r = search_dir(dirp, file_name, (ino_t *) 0, DELETE);
 27436	
 27437	  if (r == OK) {
 27438	        rip->i_nlinks--;        /* запись удалена из родительского каталога */
 27439	        rip->i_update |= CTIME;
 27440	        rip->i_dirt = DIRTY;
 27441	  }
 27442	
 27443	  put_inode(rip);
 27444	  return(r);
 27445	}





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/stadir.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 27500	/* Этот файл содержит код для выполнения четырех системных вызовов, имеющих отношение к
 27501	 * состояниям и каталогам.
 27502	 *
 27503	 * Файл имеет следующие точки входа
 27504	 *   do_chdir:   выполнение системного вызова CHDIR
 27505	 *   do_chroot:  выполнение системного вызова CHROOT
 27506	 *   do_stat:    выполнение системного вызова STAT
 27507	 *   do_fstat:   выполнение системного вызова FSTAT
 27508	 *   do_fstatfs: выполнение системного вызова FSTATFS
 27509	 */
 27510	
 27511	#include "fs.h"
 27512	#include <sys/stat.h>
 27513	#include <sys/statfs.h>
 27514	#include <minix/com.h>
 27515	#include "file.h"
 27516	#include "fproc.h"
 27517	#include "inode.h"
 27518	#include "param.h"
 27519	#include "super.h"
 27520	
 27521	FORWARD _PROTOTYPE( int change, (struct inode **iip, char *name_ptr, int len));
 27522	FORWARD _PROTOTYPE( int change_into, (struct inode **iip, struct inode *ip));
 27523	FORWARD _PROTOTYPE( int stat_inode, (struct inode *rip, struct filp *fil_ptr,
 27524	                        char *user_addr)                                );
 27525	
 27526	/*===========================================================================*
 27527	 *                              do_fchdir                                    *
 27528	 *===========================================================================*/
 27529	PUBLIC int do_fchdir()
 27530	{
 27531	        /* Изменить каталог на уже открытом дескрипторе файла. */
 27532	        struct filp *rfilp;
 27533	
 27534	        /* допустимый ли дескриптор файла? */
 27535	        if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
 27536	        return change_into(&fp->fp_workdir, rfilp->filp_ino);
 27537	}
	
 27539	/*===========================================================================*
 27540	 *                              do_chdir                                     *
 27541	 *===========================================================================*/
 27542	PUBLIC int do_chdir()
 27543	{
 27544	/* Изменение каталога. Эта функция также вызывается менеджером процессов для имитации chdir,
 27545	 * при выполнении EXEC, и т. д. Она тоже изменяет корневой каталог, uid, gid и
 27546	 * umask. 
 27547	 */
 27548	
 27549	  int r;
 27550	  register struct fproc *rfp;
 27551	
 27552	  if (who == PM_PROC_NR) {
 27553	        rfp = &fproc[m_in.slot1];
 27554	        put_inode(fp->fp_rootdir);
 27555	        dup_inode(fp->fp_rootdir = rfp->fp_rootdir);
 27556	        put_inode(fp->fp_workdir);
 27557	        dup_inode(fp->fp_workdir = rfp->fp_workdir);
 27558	
 27559	        /* Менеджер процессов использует функцию access() для проверки разрешений.
 27560	         * Для этого нужно представить, что реальный и эффективный идентификаторы
 27561	         * пользователя совпадают. Вызовы файловой системы, отличные от access(),
 27562	         * не используют реальные идентификаторы.
 27563	         */
 27564	        fp->fp_realuid =
 27565	        fp->fp_effuid = rfp->fp_effuid;
 27566	        fp->fp_realgid =
 27567	        fp->fp_effgid = rfp->fp_effgid;
 27568	        fp->fp_umask = rfp->fp_umask;
 27569	        return(OK);
 27570	  }
 27571	
 27572	  /* выполнение системного вызова chdir(name). */
 27573	  r = change(&fp->fp_workdir, m_in.name, m_in.name_length);
 27574	  return(r);
 27575	}
	
 27577	/*===========================================================================*
 27578	 *                              do_chroot                                    *
 27579	 *===========================================================================*/
 27580	PUBLIC int do_chroot()
 27581	{
 27582	/* выполнение системного вызова chroot(name). */
 27583	
 27584	  register int r;
 27585	
 27586	  if (!super_user) return(EPERM);       /* вызывать chroot() может только суперпользователь */
 27587	  r = change(&fp->fp_rootdir, m_in.name, m_in.name_length);
 27588	  return(r);
 27589	}
	
 27591	/*===========================================================================*
 27592	 *                              change                                       *
 27593	 *===========================================================================*/
 27594	PRIVATE int change(iip, name_ptr, len)
 27595	struct inode **iip;             /* указатель на индексный узел каталога */
 27596	char *name_ptr;                 /* указатель на имя целевого каталога */
 27597	int len;                        /* длина строки с именем каталога */
 27598	{
 27599	/* Выполнение фактической работы chdir() и chroot(). */
 27600	  struct inode *rip;
 27601	
 27602	  /* Попытка открыть новый каталог. */
 27603	  if (fetch_name(name_ptr, len, M3) != OK) return(err_code);
 27604	  if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
 27605	  return change_into(iip, rip);
 27606	}
	
 27608	/*===========================================================================*
 27609	 *                              change_into                                  *
 27610	 *===========================================================================*/
 27611	PRIVATE int change_into(iip, rip)
 27612	struct inode **iip;             /* указатель на индексный узел каталога */
 27613	struct inode *rip;              /* таким должен стать индексный узел */
 27614	{
 27615	  register int r;
 27616	
 27617	  /* Файл должен быть каталогом, доступным для поиска */
 27618	  if ( (rip->i_mode & I_TYPE) != I_DIRECTORY)
 27619	        r = ENOTDIR;
 27620	  else
 27621	        r = forbidden(rip, X_BIT);      /* проверка возможности поиска */
 27622	
 27623	  /* В случает ошибки вернуть индексный узел. */
 27624	  if (r != OK) {
 27625	        put_inode(rip);
 27626	        return(r);
 27627	  }
 27628	
 27629	  /* Все OK.  Выполнить изменение. */
 27630	  put_inode(*iip);              /* освободить старый каталог */
 27631	  *iip = rip;                   /* создать новый */
 27632	  return(OK);
 27633	}
	
 27635	/*===========================================================================*
 27636	 *                              do_stat                                      *
 27637	 *===========================================================================*/
 27638	PUBLIC int do_stat()
 27639	{
 27640	/* выполнение системного вызова stat(name, buf). */
 27641	
 27642	  register struct inode *rip;
 27643	  register int r;
 27644	
 27645	  /* функции stat() и fstat() используют одну и ту же процедуру для выполнения реальной
 27646	   * работы. Эта процедура принимает индексный узел, поэтому его нужно временно выделить.
 27647	   */
 27648	  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
 27649	  if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
 27650	  r = stat_inode(rip, NIL_FILP, m_in.name2);    /* фактическое выполнение работы.*/
 27651	  put_inode(rip);               /* освобождение индексного узла */
 27652	  return(r);
 27653	}
	
 27655	/*===========================================================================*
 27656	 *                              do_fstat                                     *
 27657	 *===========================================================================*/
 27658	PUBLIC int do_fstat()
 27659	{
 27660	/* выполнение системного вызова fstat(fd, buf). */
 27661	
 27662	  register struct filp *rfilp;
 27663	
 27664	  /* Является ли дескриптор файла допустимым? */
 27665	  if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
 27666	
 27667	  return(stat_inode(rfilp->filp_ino, rfilp, m_in.buffer));
 27668	}
	
 27670	/*===========================================================================*
 27671	 *                              stat_inode                                   *
 27672	 *===========================================================================*/
 27673	PRIVATE int stat_inode(rip, fil_ptr, user_addr)
 27674	register struct inode *rip;     /* указатель на индексный узел */
 27675	struct filp *fil_ptr;           /* указатель filp, возвращаемый 'fstat' */
 27676	char *user_addr;                /* адрес пользовательского пространства, где расположен буфер */
 27677	{
 27678	/* Общий код системных вызовов stat и fstat. */
 27679	
 27680	  struct stat statbuf;
 27681	  mode_t mo;
 27682	  int r, s;
 27683	
 27684	  /* Обновление полей atime, ctime и mtime индексного узла, если нужно. */
 27685	  if (rip->i_update) update_times(rip);
 27686	
 27687	  /* Заполнение структуры statbuf. */
 27688	  mo = rip->i_mode & I_TYPE;
 27689	
 27690	  /* true если специальный файл */
 27691	  s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL);
 27692	
 27693	  statbuf.st_dev = rip->i_dev;
 27694	  statbuf.st_ino = rip->i_num;
 27695	  statbuf.st_mode = rip->i_mode;
 27696	  statbuf.st_nlink = rip->i_nlinks;
 27697	  statbuf.st_uid = rip->i_uid;
 27698	  statbuf.st_gid = rip->i_gid;
 27699	  statbuf.st_rdev = (dev_t) (s ? rip->i_zone[0] :  NO_DEV);
 27700	  statbuf.st_size = rip->i_size;
 27701	
 27702	  if (rip->i_pipe == I_PIPE) {
 27703	        statbuf.st_mode &= ~I_REGULAR;  /* сброс бита I_REGULAR для каналов */
 27704	        if (fil_ptr != NIL_FILP && fil_ptr->filp_mode & R_BIT) 
 27705	                statbuf.st_size -= fil_ptr->filp_pos;
 27706	  }
 27707	
 27708	  statbuf.st_atime = rip->i_atime;
 27709	  statbuf.st_mtime = rip->i_mtime;
 27710	  statbuf.st_ctime = rip->i_ctime;
 27711	
 27712	  /* копирование структуры в пространство пользователя. */
 27713	  r = sys_datacopy(FS_PROC_NR, (vir_bytes) &statbuf,
 27714	                who, (vir_bytes) user_addr, (phys_bytes) sizeof(statbuf));
 27715	  return(r);
 27716	}
	
 27718	/*===========================================================================*
 27719	 *                              do_fstatfs                                   *
 27720	 *===========================================================================*/
 27721	PUBLIC int do_fstatfs()
 27722	{
 27723	  /* выполнение системного вызова fstatfs(fd, buf). */
 27724	  struct statfs st;
 27725	  register struct filp *rfilp;
 27726	  int r;
 27727	
 27728	  /* Допустим ли дескриптор файла? */
 27729	  if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
 27730	
 27731	  st.f_bsize = rfilp->filp_ino->i_sp->s_block_size;
 27732	
 27733	  r = sys_datacopy(FS_PROC_NR, (vir_bytes) &st,
 27734	                who, (vir_bytes) m_in.buffer, (phys_bytes) sizeof(st));
 27735	
 27736	   return(r);
 27737	}
	



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/protect.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 27800	/* Этот файл обеспечивает защиту в файловой системе. Он содержит код четырех
 27801	 * системных вызовов, осуществляющих защиту.
 27802	 *
 27803	 * Файл имеет следующие точки входа
 27804	 *   do_chmod:   выполнение симтемного вызова CHMOD
 27805	 *   do_chown:   выполнение симтемного вызова CHOWN
 27806	 *   do_umask:   выполнение симтемного вызова UMASK
 27807	 *   do_access:  выполнение симтемного вызова ACCESS
 27808	 *   forbidden:  проверка разрешения заданного доступа на заданном индексном узле
 27809	 */
 27810	
 27811	#include "fs.h"
 27812	#include <unistd.h>
 27813	#include <minix/callnr.h>
 27814	#include "buf.h"
 27815	#include "file.h"
 27816	#include "fproc.h"
 27817	#include "inode.h"
 27818	#include "param.h"
 27819	#include "super.h"
 27820	
 27821	/*===========================================================================*
 27822	 *                              do_chmod                                     *
 27823	 *===========================================================================*/
 27824	PUBLIC int do_chmod()
 27825	{
 27826	/* выполнение системного вызова chmod(name, mode). */
 27827	
 27828	  register struct inode *rip;
 27829	  register int r;
 27830	
 27831	  /* Временное открытие файла. */
 27832	  if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
 27833	  if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
 27834	
 27835	  /* Только суперпользователь может изменять файловый режим. Никто не может
 27836	   * изменять файловый режим в файловой системе только для чтения.
 27837	   */
 27838	  if (rip->i_uid != fp->fp_effuid && !super_user)
 27839	        r = EPERM;
 27840	  else
 27841	        r = read_only(rip);
 27842	
 27843	  /* В случае ошибки вернуть индексный узел. */
 27844	  if (r != OK)  {
 27845	        put_inode(rip);
 27846	        return(r);
 27847	  }
 27848	
 27849	  /* Выполнить изменение. Очистить бит setgid, если файл не в группе вызывающего процесса */
 27850	  rip->i_mode = (rip->i_mode & ~ALL_MODES) | (m_in.mode & ALL_MODES);
 27851	  if (!super_user && rip->i_gid != fp->fp_effgid)rip->i_mode &= ~I_SET_GID_BIT;
 27852	  rip->i_update |= CTIME;
 27853	  rip->i_dirt = DIRTY;
 27854	
 27855	  put_inode(rip);
 27856	  return(OK);
 27857	}
	
 27859	/*===========================================================================*
 27860	 *                              do_chown                                     *
 27861	 *===========================================================================*/
 27862	PUBLIC int do_chown()
 27863	{
 27864	/* выполнение системного вызова chown(name, owner, group). */
 27865	
 27866	  register struct inode *rip;
 27867	  register int r;
 27868	
 27869	  /* Временное открытие файла. */
 27870	  if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
 27871	  if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
 27872	
 27873	  /* Не разрешено изменять владельца файла на файловой системе только для чтения. */
 27874	  r = read_only(rip);
 27875	  if (r == OK) {
 27876	        /* Файловая система для чтения и записи. Разрешен ли вызов, зависит от владения и т. д. */
 27877	        if (super_user) {
 27878	                /* Суперпользователь может делать все. */
 27879	                rip->i_uid = m_in.owner;        /* остальные позже */
 27880	        } else {
 27881	                /* Обычные пользователи могут только изменять группу собственных файлов. */
 27882	                if (rip->i_uid != fp->fp_effuid) r = EPERM;
 27883	                if (rip->i_uid != m_in.owner) r = EPERM;  /* не отдавать */
 27884	                if (fp->fp_effgid != m_in.group) r = EPERM;
 27885	        }
 27886	  }
 27887	  if (r == OK) {
 27888	        rip->i_gid = m_in.group;
 27889	        rip->i_mode &= ~(I_SET_UID_BIT | I_SET_GID_BIT);
 27890	        rip->i_update |= CTIME;
 27891	        rip->i_dirt = DIRTY;
 27892	  }
 27893	
 27894	  put_inode(rip);
 27895	  return(r);
 27896	}
	
 27898	/*===========================================================================*
 27899	 *                              do_umask                                     *
 27900	 *===========================================================================*/
 27901	PUBLIC int do_umask()
 27902	{
 27903	/* выполнение системного вызова umask(co_mode). */
 27904	  register mode_t r;
 27905	
 27906	  r = ~fp->fp_umask;            /* запись в 'r' дополнения старой маски */
 27907	  fp->fp_umask = ~(m_in.co_mode & RWX_MODES);
 27908	  return(r);                    /* возврат дополнения старой маски */
 27909	}
	
 27911	/*===========================================================================*
 27912	 *                              do_access                                    *
 27913	 *===========================================================================*/
 27914	PUBLIC int do_access()
 27915	{
 27916	/* выполнение системного вызова access(name, mode). */
 27917	
 27918	  struct inode *rip;
 27919	  register int r;
 27920	
 27921	  /* Сначала проверка правильности режима. */
 27922	  if ( (m_in.mode & ~(R_OK | W_OK | X_OK)) != 0 && m_in.mode != F_OK)
 27923	        return(EINVAL);
 27924	
 27925	  /* Временное открытие файла, доступ к которому проверяется. */
 27926	  if (fetch_name(m_in.name, m_in.name_length, M3) != OK) return(err_code);
 27927	  if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
 27928	
 27929	  /* Проверка разрешений. */
 27930	  r = forbidden(rip, (mode_t) m_in.mode);
 27931	  put_inode(rip);
 27932	  return(r);
 27933	}
	
 27935	/*===========================================================================*
 27936	 *                              forbidden                                    *
 27937	 *===========================================================================*/
 27938	PUBLIC int forbidden(register struct inode *rip, mode_t access_desired)
 27939	{
 27940	/* По заданным указателю на индексный узел, 'rip' и интересующему доступу определить,
 27941	 * разрешен ли доступ, и если нет, то почему. Процедура ищет uid вызывающего
 27942	 * процесса в таблице 'fproc'. Если доступ разрешен, возвращается OK, в
 27943	 * противном случае EACCES.
 27944	 */
 27945	
 27946	  register struct inode *old_rip = rip;
 27947	  register struct super_block *sp;
 27948	  register mode_t bits, perm_bits;
 27949	  int r, shift, test_uid, test_gid, type;
 27950	
 27951	  if (rip->i_mount == I_MOUNT)  /* индексный узел монтирован. */
 27952	        for (sp = &super_block[1]; sp < &super_block[NR_SUPERS]; sp++)
 27953	                if (sp->s_imount == rip) {
 27954	                        rip = get_inode(sp->s_dev, ROOT_INODE);
 27955	                        break;
 27956	                } /* if */
 27957	
 27958	  /* сброс требуемых битов rwx. */
 27959	  bits = rip->i_mode;
 27960	  test_uid = (call_nr == ACCESS ? fp->fp_realuid :  fp->fp_effuid);
 27961	  test_gid = (call_nr == ACCESS ? fp->fp_realgid :  fp->fp_effgid);
 27962	  if (test_uid == SU_UID) {
 27963	        /* Установка разрешений на чтение и запись, разрешения на поиск в 
 27964	         * каталогах и разрешения на исполнение (для не каталогов) если
 27965	         * и только если установлены биты 'X'.
 27966	         */
 27967	        if ( (bits & I_TYPE) == I_DIRECTORY ||
 27968	             bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT))
 27969	                perm_bits = R_BIT | W_BIT | X_BIT;
 27970	        else
 27971	                perm_bits = R_BIT | W_BIT;
 27972	  } else {
 27973	        if (test_uid == rip->i_uid) shift = 6;          /* владелец */
 27974	        else if (test_gid == rip->i_gid ) shift = 3;    /* группа */
 27975	        else shift = 0;                                 /* остальные */
 27976	        perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
 27977	  }
 27978	
 27979	  /* Если желаемый доступ не входит в множество разрешенных, он запрещен. */
 27980	  r = OK;
 27981	  if ((perm_bits | access_desired) != perm_bits) r = EACCES;
 27982	
 27983	  /* Проверка попыток записи в файловую систему только для чтения.
 27984	   *
 27985	   */
 27986	  type = rip->i_mode & I_TYPE;
 27987	  if (r == OK)
 27988	        if (access_desired & W_BIT)
 27989	                r = read_only(rip);
 27990	
 27991	  if (rip != old_rip) put_inode(rip);
 27992	
 27993	  return(r);
 27994	}
	
 27996	/*===========================================================================*
 27997	 *                              read_only                                    *
 27998	 *===========================================================================*/
 27999	PUBLIC int read_only(ip)
 28000	struct inode *ip;      /* указатель на индексный узел, файловая система которого проверяется */
 28001	{
 28002	/* Проверка, монтирована ли файловая система, на которой находится индексный узел 'ip', только 
 28003	 * для чтения. Если да, возврат EROFS, иначе OK.
 28004	 */
 28005	
 28006	  register struct super_block *sp;
 28007	
 28008	  sp = ip->i_sp;
 28009	  return(sp->s_rd_only ? EROFS :  OK);
 28010	}

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/dmap.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 28100	/* Этот файл содержит таблицу сопоставлений устройств и драйверов, а также некоторые
 28101	 * процедуры динамического добавления и (или) удаления драйверов устройств и их
 28102	 * переназначения.  
 28103	 */
 28104	
 28105	#include "fs.h"
 28106	#include "fproc.h"
 28107	#include <string.h>
 28108	#include <stdlib.h>
 28109	#include <ctype.h>
 28110	#include <unistd.h>
 28111	#include <minix/com.h>
 28112	#include "param.h"
 28113	
 28114	/* Некоторые устройства могут как присутствовать, так и отсутствовать в следующей таблице. */
 28115	#define DT(enable, opcl, io, driver, flags) \
 28116	  { (enable?(opcl): no_dev), (enable?(io): 0), \
 28117	        (enable?(driver): 0), (flags) },
 28118	#define NC(x) (NR_CTRLRS >= (x))
 28119	
 28120	/* Порядок записей здесь определяет соответствие главных номеров устройств и заданий.
 28121	 * Первая запись (главное устройство 0) не используется. Следующая запись - главное
 28122	 * устройство 1 и т. д. Символьные и блочные устройства могут чередоваться случайным
 28123	 * образом. Порядок следования определяет номера устройств в /dev/.
 28124	 * Обратите внимание на то, что файловой системе известен номер /dev/ram/, что
 28125	 * необходимо для загрузки виртуального диска. Кроме того, главные номера устройств,
 28126	 * используемые в /dev/, НЕ совпадают с номерами процессов драйверов устройств.
 28127	 */
 28128	/*
 28129	  Driver enabled     Open/Cls  I/O     Driver #     Flags Device  File
 28130	  --------------     --------  ------  -----------  ----- ------  ----       
 28131	 */
 28132	struct dmap dmap[NR_DEVICES];                           /* фактическая карта */ 
 28133	PRIVATE struct dmap init_dmap[] = {
 28134	  DT(1, no_dev,   0,       0,           0)              /* 0 = не используется   */
 28135	  DT(1, gen_opcl, gen_io,  MEM_PROC_NR, 0)              /* 1 = /dev/mem   */
 28136	  DT(0, no_dev,   0,       0,           DMAP_MUTABLE)   /* 2 = /dev/fd0   */
 28137	  DT(0, no_dev,   0,       0,           DMAP_MUTABLE)   /* 3 = /dev/c0    */
 28138	  DT(1, tty_opcl, gen_io,  TTY_PROC_NR, 0)              /* 4 = /dev/tty00 */
 28139	  DT(1, ctty_opcl,ctty_io, TTY_PROC_NR, 0)              /* 5 = /dev/tty   */
 28140	  DT(0, no_dev,   0,       NONE,        DMAP_MUTABLE)   /* 6 = /dev/lp    */
 28141	  DT(1, no_dev,   0,       0,           DMAP_MUTABLE)   /* 7 = /dev/ip    */
 28142	  DT(0, no_dev,   0,       NONE,        DMAP_MUTABLE)   /* 8 = /dev/c1    */
 28143	  DT(0, 0,        0,       0,           DMAP_MUTABLE)   /* 9 = не используется   */
 28144	  DT(0, no_dev,   0,       0,           DMAP_MUTABLE)   /*10 = /dev/c2    */
 28145	  DT(0, 0,        0,       0,           DMAP_MUTABLE)   /*11 = не используется   */
 28146	  DT(0, no_dev,   0,       NONE,        DMAP_MUTABLE)   /*12 = /dev/c3    */
 28147	  DT(0, no_dev,   0,       NONE,        DMAP_MUTABLE)   /*13 = /dev/audio */
 28148	  DT(0, no_dev,   0,       NONE,        DMAP_MUTABLE)   /*14 = /dev/mixer */
 28149	  DT(1, gen_opcl, gen_io,  LOG_PROC_NR, 0)              /*15 = /dev/klog  */
 28150	  DT(0, no_dev,   0,       NONE,        DMAP_MUTABLE)   /*16 = /dev/random*/
 28151	  DT(0, no_dev,   0,       NONE,        DMAP_MUTABLE)   /*17 = /dev/cmos  */
 28152	};
 28153	
 28154	/*===========================================================================*
 28155	 *                              do_devctl                                    *
 28156	 *===========================================================================*/
 28157	PUBLIC int do_devctl()
 28158	{
 28159	  int result;
 28160	
 28161	  switch(m_in.ctl_req) {
 28162	  case DEV_MAP: 
 28163	      /* Попытка обновить назначение устройств. */
 28164	      result = map_driver(m_in.dev_nr, m_in.driver_nr, m_in.dev_style);
 28165	      break;
 28166	  case DEV_UNMAP: 
 28167	      result = ENOSYS;
 28168	      break;
 28169	  default: 
 28170	      result = EINVAL;
 28171	  }
 28172	  return(result);
 28173	}
	
 28175	/*===========================================================================*
 28176	 *                              map_driver                                   *
 28177	 *===========================================================================*/
 28178	PUBLIC int map_driver(major, proc_nr, style)
 28179	int major;                      /* главный номер устройства */
 28180	int proc_nr;                    /* номер процесса драйвера */
 28181	int style;                      /* стиль устройства */
 28182	{
 28183	/* Задание нового сопоставления устройства и драйвера в таблице dmap. При условии корректного
 28184	 * задания аргументов эта функция работает, только если запись может меняться и 
 28185	 * текущий драйвер не занят. 
 28186	 * Функция возвращает обычные коды ошибок, что позволяет использовать ее в системном
 28187	 * вызове, пытающемся динамически установить новый драйвер.
 28188	 */
 28189	  struct dmap *dp;
 28190	
 28191	  /* Получение указателя на запись устройства в таблице dmap. */
 28192	  if (major >= NR_DEVICES) return(ENODEV);
 28193	  dp = &dmap[major];            
 28194	        
 28195	  /* Проверка, разрешено ли обновление записи. */
 28196	  if (! (dp->dmap_flags & DMAP_MUTABLE))  return(EPERM);
 28197	  if (dp->dmap_flags & DMAP_BUSY)  return(EBUSY);
 28198	
 28199	  /* Проверка номера процесса нового драйвера. */
 28200	  if (! isokprocnr(proc_nr))  return(EINVAL);
 28201	
 28202	  /* Попытка обновить запись. */
 28203	  switch (style) {
 28204	  case STYLE_DEV:        dp->dmap_opcl = gen_opcl;       break;
 28205	  case STYLE_TTY:        dp->dmap_opcl = tty_opcl;       break;
 28206	  case STYLE_CLONE:      dp->dmap_opcl = clone_opcl;     break;
 28207	  default:               return(EINVAL);
 28208	  }
 28209	  dp->dmap_io = gen_io;
 28210	  dp->dmap_driver = proc_nr;
 28211	  return(OK); 
 28212	}
	
 28214	/*===========================================================================*
 28215	 *                              build_dmap                                   *
 28216	 *===========================================================================*/
 28217	PUBLIC void build_dmap()
 28218	{
 28219	/* Инициализация таблицы dmap всеми сопоставлениями устройств и драйверов. Затем 
 28220	 * сопоставление загрузочного драйвера контроллеру и обновление таблицы dmap. 
 28221	 * Загрузочный драйвер и контроллер, которым он управляет, задаются в мониторе
 28222	 * загрузки.  
 28223	 */
 28224	  char driver[16];
 28225	  char *controller = "c##";
 28226	  int nr, major = -1;
 28227	  int i,s;
 28228	  struct dmap *dp;
 28229	
 28230	  /* Создание таблицы с сопоставлениями устройств и драйверов. */
 28231	  for (i=0; i<NR_DEVICES; i++) {
 28232	      dp = &dmap[i];            
 28233	      if (i < sizeof(init_dmap)/sizeof(struct dmap) && 
 28234	              init_dmap[i].dmap_opcl != no_dev) {       /* предопределенный драйвер */
 28235	          dp->dmap_opcl = init_dmap[i].dmap_opcl;
 28236	          dp->dmap_io = init_dmap[i].dmap_io;
 28237	          dp->dmap_driver = init_dmap[i].dmap_driver;
 28238	          dp->dmap_flags = init_dmap[i].dmap_flags;
 28239	      } else {                                          /* ничего по умолчанию */
 28240	          dp->dmap_opcl = no_dev;
 28241	          dp->dmap_io = 0;
 28242	          dp->dmap_driver = 0;
 28243	          dp->dmap_flags = DMAP_MUTABLE;
 28244	      }
 28245	  }
 28246	
 28247	  /* Получение контроллера и драйвера из монитора загрузки. */
 28248	  if ((s = env_get_param("label", driver, sizeof(driver))) != OK) 
 28249	      panic(__FILE__,"couldn't get boot monitor parameter 'driver'", s);
 28250	  if ((s = env_get_param("controller", controller, sizeof(controller))) != OK) 
 28251	      panic(__FILE__,"couldn't get boot monitor parameter 'controller'", s);
 28252	
 28253	  /* Определение главного номера для привязки драйвера. */
 28254	  if (controller[0] == 'f' && controller[1] == 'd') {
 28255	      major = FLOPPY_MAJOR;
 28256	  } 
 28257	  else if (controller[0] == 'c' && isdigit(controller[1])) {
 28258	      if ((nr = (unsigned) atoi(&controller[1])) > NR_CTRLRS)
 28259	          panic(__FILE__,"monitor 'controller' maximum 'c#' is", NR_CTRLRS);
 28260	      major = CTRLR(nr);
 28261	  } 
 28262	  else {
 28263	      panic(__FILE__,"monitor 'controller' syntax is 'c#' of 'fd'", NO_NUM); 
 28264	  }
 28265	  
 28266	  /* Попытка фактически установить сопоставление и информирование пользователя. */
 28267	  if ((s=map_driver(major, DRVR_PROC_NR, STYLE_DEV)) != OK)
 28268	      panic(__FILE__,"map_driver failed",s);
 28269	  printf("Boot medium driver:  %s driver mapped onto controller %s.\n",
 28270	      driver, controller);
 28271	}
	



++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/device.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 28300	/* Когда нужный блок отсутствует в кэше, его необходимо считать с диска. Символьные специальные
 28301	 * файлы также требуют ввода-вывода. Функции, обеспечивающие эти действия, приведены здесь.
 28302	 *
 28303	 * Файл имеет следующие точки входа: 
 28304	 *   dev_open:    файловая система открывает устройство
 28305	 *   dev_close:   файловая система закрывает устройство
 28306	 *   dev_io:      файловая система выполняет чтение с устройства и запись на устройство
 28307	 *   dev_status:  файловая система обрабатывает оповещение о запросе обратного вызова
 28308	 *   gen_opcl:    общий вызов для открытия/закрытия
 28309	 *   gen_io:      общий вызов для выполнения операции ввода-вывода
 28310	 *   no_dev:      обработка открытия/закрытия для несуществующих устройств
 28311	 *   tty_opcl:    выполнение открытия/закрытия, специфичного для терминалов
 28312	 *   ctty_opcl:   выполнение открытия/закрытия, специфичного для управляющих терминалов
 28313	 *   ctty_io:     выполнение ввода-вывода, специфичного для управляющих терминалов
 28314	 *   do_ioctl:    выполнение системного вызова IOCTL
 28315	 *   do_setsid:   выполнение системного вызова SETSID (на стороне файловой системы)
 28316	 */
 28317	
 28318	#include "fs.h"
 28319	#include <fcntl.h>
 28320	#include <minix/callnr.h>
 28321	#include <minix/com.h>
 28322	#include "file.h"
 28323	#include "fproc.h"
 28324	#include "inode.h"
 28325	#include "param.h"
 28326	
 28327	#define ELEMENTS(a) (sizeof(a)/sizeof((a)[0]))
 28328	
 28329	extern int dmap_size;
 28330	
 28331	/*===========================================================================*
 28332	 *                              dev_open                                     *
 28333	 *===========================================================================*/
 28334	PUBLIC int dev_open(dev, proc, flags)
 28335	dev_t dev;                      /* открываемое устройство */
 28336	int proc;                       /* процесс, для которого открывается устройство */
 28337	int flags;                      /* биты режима и флаги */
 28338	{
 28339	  int major, r;
 28340	  struct dmap *dp;
 28341	
 28342	  /* Определение главного номера устройства, вызывающего зависимую от класса устройства
 28343	   * процедуру открытия/закрытия. (Это единственная процедура, которая должна проверять принадлежность
 28344	   * номера устройства к допустимому диапазону. Все остальные могут полагаться на эту проверку )
 28345	   */
 28346	  major = (dev >> MAJOR) & BYTE;
 28347	  if (major >= NR_DEVICES) major = 0;
 28348	  dp = &dmap[major];
 28349	  r = (*dp->dmap_opcl)(DEV_OPEN, dev, proc, flags);
 28350	  if (r == SUSPEND) panic(__FILE__,"suspend on open from", dp->dmap_driver);
 28351	  return(r);
 28352	}
	
 28354	/*===========================================================================*
 28355	 *                              dev_close                                    *
 28356	 *===========================================================================*/
 28357	PUBLIC void dev_close(dev)
 28358	dev_t dev;                      /* закрываемое устройство */
 28359	{
 28360	  (void) (*dmap[(dev >> MAJOR) & BYTE].dmap_opcl)(DEV_CLOSE, dev, 0, 0);
 28361	}
	
 28363	/*===========================================================================*
 28364	 *                              dev_status                                      *
 28365	 *===========================================================================*/
 28366	PUBLIC void dev_status(message *m)
 28367	{
 28368	        message st;
 28369	        int d, get_more = 1;
 28370	
 28371	        for(d = 0; d < NR_DEVICES; d++)
 28372	                if (dmap[d].dmap_driver == m->m_source)
 28373	                        break;
 28374	
 28375	        if (d >= NR_DEVICES)
 28376	                return;
 28377	
 28378	        do {
 28379	                int r;
 28380	                st.m_type = DEV_STATUS;
 28381	                if ((r=sendrec(m->m_source, &st)) != OK)
 28382	                        panic(__FILE__,"couldn't sendrec for DEV_STATUS", r);
 28383	
 28384	                switch(st.m_type) {
 28385	                        case DEV_REVIVE: 
 28386	                                revive(st.REP_PROC_NR, st.REP_STATUS);
 28387	                                break;
 28388	                        case DEV_IO_READY: 
 28389	                                select_notified(d, st.DEV_MINOR, st.DEV_SEL_OPS);
 28390	                                break;
 28391	                        default: 
 28392	                                printf("FS:  unrecognized reply %d to DEV_STATUS\n", st.m_type);
 28393	                                /* дальще. */
 28394	                        case DEV_NO_STATUS: 
 28395	                                get_more = 0;
 28396	                                break;
 28397	                }
 28398	        } while(get_more);
 28399	
 28400	        return;
 28401	}
	
 28403	/*===========================================================================*
 28404	 *                              dev_io                                       *
 28405	 *===========================================================================*/
 28406	PUBLIC int dev_io(op, dev, proc, buf, pos, bytes, flags)
 28407	int op;                         /* DEV_READ, DEV_WRITE, DEV_IOCTL и т. д. */
 28408	dev_t dev;                      /* главный-вспомогательный номер устройства */
 28409	int proc;                       /* в чьем адресном пространстве находится буфер? */
 28410	void *buf;                      /* виртуальный адрес буфера */
 28411	off_t pos;                      /* байтовая позиция */
 28412	int bytes;                      /* число передаваемых байтов */
 28413	int flags;                      /* специальные флаги, например, O_NONBLOCK */
 28414	{
 28415	/* Чтение с устройства или запись на устройство, определяемое параметром 'dev'. */
 28416	  struct dmap *dp;
 28417	  message dev_mess;
 28418	
 28419	  /* Определение dmap задания. */
 28420	  dp = &dmap[(dev >> MAJOR) & BYTE];
 28421	
 28422	  /* Создание сообщения, передаваемого заданию. */
 28423	  dev_mess.m_type   = op;
 28424	  dev_mess.DEVICE   = (dev >> MINOR) & BYTE;
 28425	  dev_mess.POSITION = pos;
 28426	  dev_mess.PROC_NR  = proc;
 28427	  dev_mess.ADDRESS  = buf;
 28428	  dev_mess.COUNT    = bytes;
 28429	  dev_mess.TTY_FLAGS = flags;
 28430	
 28431	  /* Вызов задания. */
 28432	  (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
 28433	
 28434	  /* Задание завершено. Проверка, выполнен ли вызов. */
 28435	  if (dev_mess.REP_STATUS == SUSPEND) {
 28436	        if (flags & O_NONBLOCK) {
 28437	                /* Блокировка не предполагается. */
 28438	                dev_mess.m_type = CANCEL;
 28439	                dev_mess.PROC_NR = proc;
 28440	                dev_mess.DEVICE = (dev >> MINOR) & BYTE;
 28441	                (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
 28442	                if (dev_mess.REP_STATUS == EINTR) dev_mess.REP_STATUS = EAGAIN;
 28443	        } else {
 28444	                /* Приостановка пользователя. */
 28445	                suspend(dp->dmap_driver);
 28446	                return(SUSPEND);
 28447	        }
 28448	  }
 28449	  return(dev_mess.REP_STATUS);
 28450	}
	
 28452	/*===========================================================================*
 28453	 *                              gen_opcl                                     *
 28454	 *===========================================================================*/
 28455	PUBLIC int gen_opcl(op, dev, proc, flags)
 28456	int op;                         /* операция, DEV_OPEN или DEV_CLOSE */
 28457	dev_t dev;                      /* открываемое/закрываемое устройство */
 28458	int proc;                       /* процесс, для которого открывается/закрывается устройство */
 28459	int flags;                      /* биты режима и флаги */
 28460	{
 28461	/* Эта процедура вызывается из структуры dmap в файле table.c при открытии и закрытии специальных файлов.*/
 28462	  struct dmap *dp;
 28463	  message dev_mess;
 28464	
 28465	  /* Определение dmap задания */
 28466	  dp = &dmap[(dev >> MAJOR) & BYTE];
 28467	
 28468	  dev_mess.m_type   = op;
 28469	  dev_mess.DEVICE   = (dev >> MINOR) & BYTE;
 28470	  dev_mess.PROC_NR  = proc;
 28471	  dev_mess.COUNT    = flags;
 28472	
 28473	  /* Вызов задания. */
 28474	  (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
 28475	
 28476	  return(dev_mess.REP_STATUS);
 28477	}
	
 28479	/*===========================================================================*
 28480	 *                              tty_opcl                                     *
 28481	 *===========================================================================*/
 28482	PUBLIC int tty_opcl(op, dev, proc, flags)
 28483	int op;                         /* операция, DEV_OPEN или DEV_CLOSE */
 28484	dev_t dev;                      /* открываемое/закрываемое устройство */
 28485	int proc;                       /* процесс, для которого открывается/закрывается устройство */
 28486	int flags;                      /* биты режима и флаги */
 28487	{
 28488	/* Эта процедура вызывается из структуры dmap при открытии и закрытии терминалов. */
 28489	 
 28490	  int r;
 28491	  register struct fproc *rfp;
 28492	
 28493	  /* Установка флага O_NOCTTY, если этот процесс не является лидером сеанса, уже
 28494	   * имеет управляющий терминал либо терминал уже является управляющим для другого 
 28495	   * процесса.
 28496	   */
 28497	  if (!fp->fp_sesldr || fp->fp_tty != 0) {
 28498	        flags |= O_NOCTTY;
 28499	  } else {
 28500	        for (rfp = &fproc[0]; rfp < &fproc[NR_PROCS]; rfp++) {
 28501	                if (rfp->fp_tty == dev) flags |= O_NOCTTY;
 28502	        }
 28503	  }
 28504	
 28505	  r = gen_opcl(op, dev, proc, flags);
 28506	
 28507	  /* Сделал ли этот вызов терминал управляющим? */
 28508	  if (r == 1) {
 28509	        fp->fp_tty = dev;
 28510	        r = OK;
 28511	  }
 28512	  return(r);
 28513	}
	
 28515	/*===========================================================================*
 28516	 *                              ctty_opcl                                    *
 28517	 *===========================================================================*/
 28518	PUBLIC int ctty_opcl(op, dev, proc, flags)
 28519	int op;                         /* операция, DEV_OPEN или DEV_CLOSE */
 28520	dev_t dev;                      /* открываемое/закрываемое устройство */
 28521	int proc;                       /* процесс, для которого открывается/закрывается устройство */
 28522	int flags;                      /* биты режима и флаги */
 28523	{
 28524	/* Эта процедура вызывается из структуры dmap в файле table.c при открытии и закрытии
 28525	 * /dev/tty, магического устройства, обеспечивающего назначение управляющих терминалов.
 28526	 */
 28527	 
 28528	  return(fp->fp_tty == 0 ? ENXIO :  OK);
 28529	}
	
 28531	/*===========================================================================*
 28532	 *                              do_setsid                                    *
 28533	 *===========================================================================*/
 28534	PUBLIC int do_setsid()
 28535	{
 28536	/* Выполнение части вызова SETSID на файловой системе: избавление от управляющего терминала
 28537	 * процесса и назначение процесса лидером сеанса.
 28538	 */
 28539	  register struct fproc *rfp;
 28540	
 28541	  /* Только менеджер процессов может выполнять вызов SETSID напрямую. */
 28542	  if (who != PM_PROC_NR) return(ENOSYS);
 28543	
 28544	  /* Назначение процесса лидером сеанса без управляющего терминала. */
 28545	  rfp = &fproc[m_in.slot1];
 28546	  rfp->fp_sesldr = TRUE;
 28547	  rfp->fp_tty = 0;
 28548	  return(OK);
 28549	}
	
 28551	/*===========================================================================*
 28552	 *                              do_ioctl                                     *
 28553	 *===========================================================================*/
 28554	PUBLIC int do_ioctl()
 28555	{
 28556	/* выполнение системного вызова ioctl(ls_fd, request, argx) (использует формат m2). */
 28557	
 28558	  struct filp *f;
 28559	  register struct inode *rip;
 28560	  dev_t dev;
 28561	
 28562	  if ( (f = get_filp(m_in.ls_fd)) == NIL_FILP) return(err_code);
 28563	  rip = f->filp_ino;            /* получение указателя на индексный узел */
 28564	  if ( (rip->i_mode & I_TYPE) != I_CHAR_SPECIAL
 28565	        && (rip->i_mode & I_TYPE) != I_BLOCK_SPECIAL) return(ENOTTY);
 28566	  dev = (dev_t) rip->i_zone[0];
 28567	
 28568	  return(dev_io(DEV_IOCTL, dev, who, m_in.ADDRESS, 0L, 
 28569	        m_in.REQUEST, f->filp_flags));
 28570	}
	
 28572	/*===========================================================================*
 28573	 *                              gen_io                                       *
 28574	 *===========================================================================*/
 28575	PUBLIC void gen_io(task_nr, mess_ptr)
 28576	int task_nr;                    /* вызываемое задание */
 28577	message *mess_ptr;              /* указатель на сообщение для задания */
 28578	{
 28579	/* Весь ввод-вывод файловой системы в конечном счете сводится к вводу-выводу на пару
 28580	 * "главное-вспомогательное устройство".  Это приводит к вызовам следующих функций через таблицу dmap.
 28581	 */
 28582	
 28583	  int r, proc_nr;
 28584	  message local_m;
 28585	
 28586	  proc_nr = mess_ptr->PROC_NR;
 28587	  if (! isokprocnr(proc_nr)) {
 28588	      printf("FS:  warning, got illegal process number (%d) from %d\n",
 28589	          mess_ptr->PROC_NR, mess_ptr->m_source);
 28590	      return;
 28591	  }
 28592	
 28593	  while ((r = sendrec(task_nr, mess_ptr)) == ELOCKED) {
 28594	        /* sendrec() не удалось предотвратить взаимную блокировку. Задание 'task_nr'
 28595	         * пытается отправить сообщение REVIVE для более раннего запроса. Его обработка
 28596	         * и повторная попытка.
 28597	         */
 28598	        if ((r = receive(task_nr, &local_m)) != OK) {
 28599	                break;
 28600	        }
 28601	
 28602	        /* Если мы пытаемся послать сообщение об отмене задание, которое только что
 28603	         * отправило ответ о завершении действия, игнорировать ответ и аннулировать
 28604	         * запрос об отмене. Вызывающий процесс разбудит этот процесс.
 28605	         */
 28606	        if (mess_ptr->m_type == CANCEL && local_m.REP_PROC_NR == proc_nr) {
 28607	                return;
 28608	        }
 28609	
 28610	        /* Иначе REVIVE. */
 28611	        if (local_m.m_type != REVIVE) {
 28612	                printf(
 28613	                "fs:  strange device reply from %d, type = %d, proc = %d (1)\n",
 28614	                        local_m.m_source,
 28615	                        local_m.m_type, local_m.REP_PROC_NR);
 28616	                continue;
 28617	        }
 28618	
 28619	        revive(local_m.REP_PROC_NR, local_m.REP_STATUS);
 28620	  }
 28621	
 28622	  /* Полученное сообщение может быть ответом на этот вызов, либо REVIVE для какого-то
 28623	   * другого процесса.
 28624	   */
 28625	  for (;;) {
 28626	        if (r != OK) {
 28627	                if (r == EDEADDST) return;      /* отказ */
 28628	                else panic(__FILE__,"call_task:  can't send/receive", r);
 28629	        }
 28630	
 28631	        /* Получил ли результат процесс, для которого мы выполнили sendrec()? */
 28632	        if (mess_ptr->REP_PROC_NR == proc_nr) {
 28633	                break;
 28634	        } else if (mess_ptr->m_type == REVIVE) {
 28635	                /* Иначе REVIVE. */
 28636	                revive(mess_ptr->REP_PROC_NR, mess_ptr->REP_STATUS);
 28637	        } else {
 28638	                printf(
 28639	                "fs:  strange device reply from %d, type = %d, proc = %d (2)\n",
 28640	                        mess_ptr->m_source,
 28641	                        mess_ptr->m_type, mess_ptr->REP_PROC_NR);
 28642	                return;
 28643	        }
 28644	
 28645	        r = receive(task_nr, mess_ptr);
 28646	  }
 28647	}
	
 28649	/*===========================================================================*
 28650	 *                              ctty_io                                      *
 28651	 *===========================================================================*/
 28652	PUBLIC void ctty_io(task_nr, mess_ptr)
 28653	int task_nr;                    /* не используется – для совместимости с dmap_t */
 28654	message *mess_ptr;              /* указатель на сообщение для задание */
 28655	{
 28656	/* Эта процедура вызывается только для одного устройства, /dev/tty.  Ее задача - сделать
 28657	 * так, чтобы сообщение использовало управляющий терминал вместо пары главное/вспомогательное
 28658	 * числа самого устройства /dev/tty.
 28659	 */
 28660	
 28661	  struct dmap *dp;
 28662	
 28663	  if (fp->fp_tty == 0) {
 28664	        /* Управляющего терминала больше нет, возврат ошибки. */
 28665	        mess_ptr->REP_STATUS = EIO;
 28666	  } else {
 28667	        /* Подстановка устройства управляющего терминала. */
 28668	        dp = &dmap[(fp->fp_tty >> MAJOR) & BYTE];
 28669	        mess_ptr->DEVICE = (fp->fp_tty >> MINOR) & BYTE;
 28670	        (*dp->dmap_io)(dp->dmap_driver, mess_ptr);
 28671	  }
 28672	}
	
 28674	/*===========================================================================*
 28675	 *                              no_dev                                       *
 28676	 *===========================================================================*/
 28677	PUBLIC int no_dev(op, dev, proc, flags)
 28678	int op;                         /* операция, DEV_OPEN или DEV_CLOSE */
 28679	dev_t dev;                      /* открываемое/закрываемое устройство */
 28680	int proc;                       /* процесс, для которого открывается/закрывается устройство */
 28681	int flags;                      /* биты режима и флаги */
 28682	{
 28683	/* Вызывается при открытии несуществующего устройства. */
 28684	
 28685	  return(ENODEV);
 28686	}
	
 28688	/*===========================================================================*
 28689	 *                              clone_opcl                                   *
 28690	 *===========================================================================*/
 28691	PUBLIC int clone_opcl(op, dev, proc, flags)
 28692	int op;                         /* операция, DEV_OPEN или DEV_CLOSE */
 28693	dev_t dev;                      /* открываемое/закрываемое устройство */
 28694	int proc;                       /* процесс, для которого открывается/закрывается устройство */
 28695	int flags;                      /* биты режима и флаги */
 28696	{
 28697	/* Какому-то устройству необходима особая обработка операции открытия. Такое устройство
 28698	 * "клонируется", то есть при открытии замещается новым устройством с уникальным
 28699	 * вспомогательным номером. Этот новый вспомогательный номер идентифицирует новый объект (такой, 
 28700	 * как новое сетевое соединение), выделенный внутри задания.
 28701	 */
 28702	  struct dmap *dp;
 28703	  int minor;
 28704	  message dev_mess;
 28705	
 28706	  /* Определение dmap задания. */
 28707	  dp = &dmap[(dev >> MAJOR) & BYTE];
 28708	  minor = (dev >> MINOR) & BYTE;
 28709	
 28710	  dev_mess.m_type   = op;
 28711	  dev_mess.DEVICE   = minor;
 28712	  dev_mess.PROC_NR  = proc;
 28713	  dev_mess.COUNT    = flags;
 28714	
 28715	  /* Вызов задания. */
 28716	  (*dp->dmap_io)(dp->dmap_driver, &dev_mess);
 28717	
 28718	  if (op == DEV_OPEN && dev_mess.REP_STATUS >= 0) {
 28719	        if (dev_mess.REP_STATUS != minor) {
 28720	                /* Возвращен новый вспомогательный номер устройства. Создание временного
 28721	                 * файла устройства для его хранения.
 28722	                 */
 28723	                struct inode *ip;
 28724	
 28725	                /* Номер нового устройства. */
 28726	                dev = (dev & ~(BYTE << MINOR)) | (dev_mess.REP_STATUS << MINOR);
 28727	
 28728	                ip = alloc_inode(root_dev, ALL_MODES | I_CHAR_SPECIAL);
 28729	                if (ip == NIL_INODE) {
 28730	                        /* Не сработало, отмена открытия. */
 28731	                        (void) clone_opcl(DEV_CLOSE, dev, proc, 0);
 28732	                        return(err_code);
 28733	                }
 28734	                ip->i_zone[0] = dev;
 28735	
 28736	                put_inode(fp->fp_filp[m_in.fd]->filp_ino);
 28737	                fp->fp_filp[m_in.fd]->filp_ino = ip;
 28738	        }
 28739	        dev_mess.REP_STATUS = OK;
 28740	  }
 28741	  return(dev_mess.REP_STATUS);
 28742	}
	





++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                                      servers/fs/time.c
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

 28800	/* Этот файл обрабатывает системные вызовы, имеющие отношение ко времени.
 28801	 *
 28802	 * Файл имеет следующие точки входа:
 28803	 *   do_utime:           выполнение системного вызово UTIME
 28804	 *   do_stime:           менеджер процессов информирует файловую систему о системном вызове STIME
 28805	 */
 28806	
 28807	#include "fs.h"
 28808	#include <minix/callnr.h>
 28809	#include <minix/com.h>
 28810	#include "file.h"
 28811	#include "fproc.h"
 28812	#include "inode.h"
 28813	#include "param.h"
 28814	
 28815	/*===========================================================================*
 28816	 *                              do_utime                                     *
 28817	 *===========================================================================*/
 28818	PUBLIC int do_utime()
 28819	{
 28820	/* выполнение системного вызова utime(name, timep). */
 28821	
 28822	  register struct inode *rip;
 28823	  register int len, r;
 28824	
 28825	  /* Особый случай: 'timep' == NULL;
 28826	   * тогда utime_strlen содержит фактический размер:  strlen(name)+1.
 28827	   */
 28828	  len = m_in.utime_length;
 28829	  if (len == 0) len = m_in.utime_strlen;
 28830	
 28831	  /* Временное открытие файла. */
 28832	  if (fetch_name(m_in.utime_file, len, M1) != OK) return(err_code);
 28833	  if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
 28834	
 28835	  /* Только владелец файла и суперпользователь могут изменять атрибуты времени файла. */
 28836	  r = OK;
 28837	  if (rip->i_uid != fp->fp_effuid && !super_user) r = EPERM;
 28838	  if (m_in.utime_length == 0 && r != OK) r = forbidden(rip, W_BIT);
 28839	  if (read_only(rip) != OK) r = EROFS;  /* not even su can touch if R/O */
 28840	  if (r == OK) {
 28841	        if (m_in.utime_length == 0) {
 28842	                rip->i_atime = clock_time();
 28843	                rip->i_mtime = rip->i_atime;
 28844	        } else {
 28845	                rip->i_atime = m_in.utime_actime;
 28846	                rip->i_mtime = m_in.utime_modtime;
 28847	        }
 28848	        rip->i_update = CTIME;  /* отмена неактуальных флагов ATIME и MTIME */
 28849	        rip->i_dirt = DIRTY;
 28850	  }
 28851	
 28852	  put_inode(rip);
 28853	  return(r);
 28854	}
	
 28856	/*===========================================================================*
 28857	 *                              do_stime                                     *
 28858	 *===========================================================================*/
 28859	PUBLIC int do_stime()
 28860	{
 28861	/* Выполнение системного вызова stime(tp). */
 28862	  boottime = (long) m_in.pm_stime; 
 28863	  return(OK);
 28864	}

