Rubini
Информация основывается на версии Linux 1.0 .
При включении процессор 80x86 загружается в real mode по биос-адресу 0xFFFF0.
Биос тестирует систему и инициализирует вектор прерывания по адресу 0.
После этого биос грузит код с первого сектора загрузочного устройства(дискеты или харда) в память по адресу 0x7C00 и прыгает в этот адрес. boot/bootsect.S написан на асм-е.
Загрузчик первым делом клонирует себя по адресу 0x90000, затем загружает очередную порцию кода - 2Кб -
с загрузочного устройства по адресу 0x90200, а остальную чать - по адресу 0x10000.
Контроль передается в boot/Setup.S. Здесь пользователю может быть предложен выбор видео-режима.
Затем происходит клонирование кода с адреса 0x10000 по адресу 0x1000 , устанавливается защищенный режим
и запускается адрес 0x1000.
Следующий шаг - декомпрессия ядра . zBoot/head.S инициализирует регистры и вызывает decompress_kernel().
Архив копируется по адресу 0x100000 (1 Meg),и это основная причина, по которой линукс не может работать на системах ,
на которых меньше 2 метров памяти :-)
Этот код запускается , при этом инициализируются таблицы IDT, GDT, LDT , пэйджинг .
На этом этапе ошибок быть не должно , иначе процессор упадет в ступор .
Все дальнейшее - на си . Вызывается start_kernel из init/main.c . Вызывается paging_init() , IRQ ,
парсится командная строка , инициализируются устройства , После чего вызывается move_to_user_mode() ,
генерится init-процесс "idle" с нулевым id-шником.
init-процесс пытается запуститься по одному из адресов /etc/init, /bin/init, /sbin/init.
Ежели это не удается , вываливается shell и нет никакой возможности залогиниться вновь .
Далее ядро ожидает системных вызовов от запущенных пользовательских процессов .
С точки зрения ядра , пользовательский процесс - это адрес в таблице процессов , и ничего более .
Таблица процессов-это массив структур task_struct . Также можно сказать , что таблица процессов -
это древовидная структура , построенная на основе double-linked списков , физически это массив указателей ,
и каждая структура хранится в отдельной странице памяти . Перемещаться по этому массиву можно с помощью
указателей next_task и prev_task .
Существует глобальный указатель "current" , который всегда указывает на процесс , выполняемый в данный момент .
Значение current может быть изменено в kernel/sched.c . Для того , чтобы сделать обзор всех процессов ,
нужно использовать макрос for_each_task . Процесс может выполняться либо в user mode'', либо в ``kernel mode''.
Код пользовательских программ выполняется в user mode'', системные вызовы в них - в ``kernel mode''.
Внутри этого процесса стек может быть различным - в зависимости от mode . Стек ядра никогда не своппится .
Системный вызов начинается с префикса `sys_'. Новый процесс создается с помощью системного вызова fork() ,
прекращение процесса - спомощью exit() или специального сигнала . Реализация - в kernel/fork.c и kernel/exit.c.
Для структуры task_struct выделяется место , вызывается find_empty_process() для нахождения пустого слота ,
выделяется страница для kernel_stack_page , запоминается родительский процесс для возвращения .
В файле exit.c лежат функции для выхода sys_kill() , sys_wait(), sys_exit() .
Как правило , при запуске пользовательского процесса параллельно запускается 2-й процесс - exec().
Его роль заключается в том , чтобы загрузить с харда и запустить образ исполняемого бинарного файла .
Поддерживаются различные бинарные форматы , для этого есть структура linux_binfmt , в которой есть 2 указателя
на функции загрузки бинарника и соответствующей библиотеки . sys_execve() определяет первые 2 байта бинарника ,
и если это ``#!'' , то запускается интерпретатор .
Если что-то набирается в консоли , вызывается con_write() , которая идентифицирует набираемые символы.
Обмен между видеопамятью и консолью осуществляют set_scrmem() и get_scrmem().
По поводу клавиатуры привожу цитату : "Keyboard management is quite a nightmare".
За это в версии 1.0 отвечает файл keyboard.c , который состоит из 16-ричных кодовых представлений от различных
производителей . Переключение между консолями выполняет change_console() и complete_change_console() (tty_io.c) .
Системный вызов ioctl() (fs/ioctl.c) позволяет пользовательским программам контролировать устройства .
|
|