++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/ansi.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 00000 /* Заголовочный файл помогает выяснить, достаточно ли компилятор совместим 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 /* В заголовочном файле определены некоторые базовые размеры 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 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 /* В заголовочном файле определены коды различных ошибок, которые могут 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 /* проверка, не включен ли заголовок ранее */ 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 /* Заголовочный файл содержит несколько макроконстант. */ 00401 00402 #ifndef _UNISTD_H 00403 #define _UNISTD_H 00404 00405 #ifndef _TYPES_H 00406 #include 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 должно быть определено в согласно 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 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 /* Заголовочный файл содержит прототипы функций 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 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 /* Заголовочный файл определяет все сигналы ANSI и POSIX. 00701 * MINIX поддерживает все сигналы, требуемые POSIX. Они определены далее. 00702 * Поддерживаются также некоторые дополнительные сигналы. 00703 */ 00704 00705 #ifndef _SIGNAL_H 00706 #define _SIGNAL_H 00707 00708 #ifndef _ANSI_H 00709 #include 00710 #endif 00711 #ifdef _POSIX_SOURCE 00712 #ifndef _TYPES_H 00713 #include 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 /* Заголовочный файл необходим системным вызовам 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 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 /* Заголовочный файл используется для управления режимами терминала. */ 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 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 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 01318 #include 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 /* Заголовочный файл содержит важные определения типов данных. 01401 * Использование этих определений вместо базовых типов данных считается 01402 * хорошей практикой программирования. По соглашению все имена типов имеют 01403 * окончание _t. 01404 */ 01405 01406 #ifndef _TYPES_H 01407 #define _TYPES_H 01408 01409 #ifndef _ANSI_H 01410 #include 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 01610 #endif 01611 01612 #ifndef _MINIX_SYS_CONFIG_H 01613 #include 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. Они должны согласовываться с файлом . */ 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 /* Заголовочный файл определяет структуру, используемую в функциях stat() 01701 * и fstat. Информация, хранимая в структуре, извлекается из индексного узла некоторого файла. 01702 * Данные вызовы являются единственно одобренным способом получения данных индексных узлов. 01703 */ 01704 01705 #ifndef _STAT_H 01706 #define _STAT_H 01707 01708 #ifndef _TYPES_H 01709 #include 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 /* Заголовочный файл описывает структуру каталога. */ 01801 01802 #ifndef _DIR_H 01803 #define _DIR_H 01804 01805 #include 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 /* Заголовочный файл содержит макросы, связанные с функцией 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 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 /* 'T' 't' 'k' */ 02016 #include /* 'd' */ 02017 #include /* 'm' */ 02018 #include /* '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 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 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 * . 02325 */ 02326 #include 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 please define _MINIX_MACHINE" 02541 #endif 02542 02543 #ifndef _MINIX_CHIP 02544 error "In 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 02805 #endif 02806 02807 #ifndef _TYPES_H 02808 #include 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 03207 #endif 03208 03209 #ifndef _IPC_H 03210 #include 03211 #endif 03212 03213 #ifndef _DEVIO_H 03214 #include 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 находится в . */ 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 /* необходимо включить */ 04112 #include /* необходимы типы 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 * Также см. файл , содержащий функции для байтов, слов и данных 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 04204 #include 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 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 /* глобальная конфигурация, ДОЛЖНА быть первой */ 04612 #include /* стиль C: ANSI или К&Р, ДОЛЖЕН быть вторым */ 04613 #include /* общие системные типы */ 04614 #include /* специфические константы MINIX */ 04615 #include /* специфические типы MINIX, например, сообщения */ 04616 #include /* система реального времени MINIX */ 04617 #include /* управление сторожевым таймером */ 04618 #include /* коды возврата и номера ошибок */ 04619 #include /* ввод (вывод) с (на) устройства и управление прерываниями */ 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 /* номера прерываний и аппаратные векторы */ 04805 #include /* адреса портов и магические номера */ 04806 #include /* адреса, размеры и магические числа BIOS*/ 04807 #include /* адреса, размеры и магические числа BIOS */ 04808 #include 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 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 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 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 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 06034 #include 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 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 06355 #include 06356 #include 06357 #include 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< 06914 #include 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 07116 #include 07117 #include 07118 #include 07119 #include 07120 #include 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; rps_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 07439 #include 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<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 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 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 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 08806 #include 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<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 09415 #include "kernel.h" 09416 #include 09417 #include 09418 #include 09419 #include 09420 #include 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 09733 #include 09734 #include 09735 #include 09736 #include 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<= 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; is_alarm_timer)); 09815 } 09816 09817 /* Инициализация вектора вызовов безопасным обработчиком по умолчанию. Некоторые вызовы 09818 * ядра могут быть отключены или не существовать. В этом случае известным вызовам явно 09819 * назначаются функции-обработчики. Это делается с помощью макроса, приводящего к ошибке 09820 * компиляции, если номер вызова некорректен. Очередность инициализации не имеет значения. 09821 */ 09822 for (i=0; is_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 10311 #include 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, "", 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 10434 #include 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, которую обрабатывают функции файла . 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 /* получение отрицательного номера ошибки в */ 10706 10707 /* Основные заголовочные файлы, включаемые в файлы *.c автоматически. */ 10708 #include /* ДОЛЖЕН быть первым */ 10709 #include /* ДОЛЖЕН быть вторым */ 10710 #include 10711 #include 10712 #include 10713 #include 10714 #include 10715 #include 10716 #include 10717 #include 10718 #include 10719 #include 10720 10721 #include /* векторы прерываний и различные порты */ 10722 #include /* индексы BIOS */ 10723 #include /* зарезервированные порты */ 10724 10725 #include 10726 #include 10727 #include 10728 #include 10729 #include 10730 #include 10731 #include 10732 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/libdriver/driver.h ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 10800 /* Типы и константы, используемые общим и зависимым от устройств кодом драйверов 10801 * устройств. 10802 */ 10803 10804 #define _POSIX_SOURCE 1 /* заголовочные файлы должны включать содержимое для POSIX */ 10805 #define _MINIX 1 /* заголовочные файлы должны включать содержимое для MINIX */ 10806 #define _SYSTEM 1 /* получение отрицательного номера ошибки в */ 10807 10808 /* Основные заголовочные файлы, включаемые в файлы *.c автоматически. */ 10809 #include /* ДОЛЖЕН быть первым */ 10810 #include /* ДОЛЖЕН быть вторым */ 10811 #include 10812 #include 10813 #include 10814 #include 10815 #include 10816 #include 10817 #include 10818 #include 10819 10820 #include 10821 #include 10822 #include 10823 #include 10824 10825 #include 10826 #include 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 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 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 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 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; iDEVICE)) == 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 12120 #include 12121 #include 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 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 /* из */ 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 13661 #include 13662 #include 13663 #include 13664 #include 13665 #include "tty.h" 13666 13667 #include 13668 #include 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) ¶m.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) ¶m.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 15210 #include 15211 #include 15212 #include 15213 #include 15214 #include 15215 #include 15216 #include 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 * уже определены в файле и их легко расширить в будущем. 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", ""); 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", ""); 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 15920 #include 15921 #include 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 /* ДОЛЖЕН быть первым */ 17009 #include /* ДОЛЖЕН быть вторым */ 17010 #include 17011 #include 17012 #include 17013 17014 #include 17015 #include 17016 #include 17017 #include 17018 17019 #include 17020 #include 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 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 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 17808 #include 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 18013 #include 18014 #include 18015 #include 18016 #include 18017 #include 18018 #include 18019 #include 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 18417 #include 18418 #include 18419 #include 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 18720 #include 18721 #include 18722 #include 18723 #include 18724 #include 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 * определен в . Он включает 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 /* Процесс, который является исполняемым файлом . Процесс 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 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 19524 #include 19525 #include 19526 #include 19527 #include 19528 #include 19529 #include 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, ¤t_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 20218 #include 20219 #include 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 20310 #include 20311 #include 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 20408 #include 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 20514 #include 20515 #include 20516 #include 20517 #include 20518 #include 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 /* ДОЛЖЕН быть первым */ 20911 #include /* ДОЛЖЕН быть вторым */ 20912 #include 20913 #include 20914 #include 20915 #include 20916 20917 #include 20918 #include 20919 20920 #include 20921 #include 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 21614 #include 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 22208 #include 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 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 23315 #include 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 23809 #include 23810 #include 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 24014 #include 24015 #include 24016 #include 24017 #include 24018 #include 24019 #include 24020 #include 24021 #include 24022 #include 24023 #include 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 24514 #include 24515 #include 24516 #include 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 25015 #include 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 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 25918 #include 25919 #include 25920 #include 25921 #include 25922 #include 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 26312 #include 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 26709 #include 26710 #include 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 27013 #include 27014 #include 27015 #include 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 27513 #include 27514 #include 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 27813 #include 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 28108 #include 28109 #include 28110 #include 28111 #include 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; idmap_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 28320 #include 28321 #include 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 28809 #include 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 }