48552 (588566), страница 15
Текст из файла (страница 15)
Операционная система состоит из следующих компонентов:
"Собственно ядро"
Драйвера устройств
Системные вызовы
В зависимости от организации внутренних взаимодействий, ядра подразделяются на "микроядра" (microkernel) и монолитные ядра.
Системы с "микроядром" строятся по модульному принципу, имеют обособленное ядро, и механизм взаимодействия между драйверами устройств и процессами. По такому принципу строятся системы реального времени. Примерно так сделан QNX или HURD.
Монолитное ядро имеет более жесткую внутреннюю структуру. Все установленные драйвера жестко связываются между собой, обычно прямыми вызовами. По таким принципам строятся обыкновенные операционные системы типа Linux, FreeBSD.
Естественно, не все так четко, идеального монолитного или "микроядра" нет, наверное, ни в одной системе, просто системы приближаются к тому или иному типу ядра.
Один, отдельно взятый, процессор, в один момент времени, может исполнять только одну программу. Но к компьютерам предъявляются более широкие требования. Мало кто, в настоящее время, удовлетворился однозадачной операционной системой (к каким относился DOS, например). В связи с этим разработчики процессоров предусмотрели мультизадачные возможности.
Возможность эта заключается в том, что процессор выполняет какую-то одну программу (их еще называют процессами или задачами). Затем, по истечении некоторого времени (обычно это время меряется микросекундами), операционная система переключает процессор на другую программу. При этом все регистры текущей программы сохраняются. Это необходимо для того, чтобы через некоторое время вновь передать управление этой программе. Программа при этом не замечает каких либо изменений, для нее процесс переключения остается незаметен.
Для того чтобы программа не могла, каким либо образом, нарушить работоспособность системы или других программ, разработчики процессоров предусмотрели механизмы защиты.
Процессор предоставляет 4 "кольца защиты" (уровня привилегий), можно было бы использовать все, но это связано со сложностями взаимодействия программ разного уровня защиты. Поэтому в большинстве существующих систем используют два уровня.0 - привилегированный уровень (ядро) и 3 - непривилегированный (пользовательские программы).
Всем этим обеспечивается надежное функционирование системы и независимость программ друг от друга.
На "Собственно ядро" возлагаются функции менеджера памяти и процессов. Переключение процессов - это основной момент нормального функционирования системы. Драйвера не должны "тормозить", а тем более блокировать работу ядра. Windows - наглядный пример того, что этого нельзя допустить!
Теперь о драйверах. Драйвера - это специальные программы, обеспечивающие работу устройств компьютера. В существующих системах (во FreeBSD это точно есть, про Linux не уверен) предусматриваются механизмы прерывания работы драйверов по истечении какого-то времени. Правда, все зависит от того, как написан драйвер. Можно написать драйвер под FreeBSD или Linux, который полностью блокирует работу системы.
Избежать этого при двухуровневой защите не представляется возможным, поэтому драйвера надо будет тщательно программировать. В нашей работе драйверам мы уделим очень много внимания, поскольку от этого в основном зависит общая производительность системы.
Системные вызовы - это интерфейс между процессами и ядром (читайте-железом). Никаких других методов взаимодействия процессов с устройствами компьютера быть не должно. Системных вызовов достаточно много, на Linux их 190, на FreeBSD их порядка 350, причем большей частью они совпадают, соответствуя стандарту POSIX (стандарт, описывающий системные вызовы в UNIX). Разница заключается в передаче параметров, что легко будет предусмотреть. Естественно, мы не сможем сделать ядро, работающее одновременно на Linux и на FreeBSD, но по отдельности совместимость вполне реализуема.
Прикладным программам абсолютно безразлично, как системные вызовы реализуются в ядре. Это облегчает для нас обеспечение совместимости с существующими системами.
Ядро системы при распределении памяти оперирует 4-х килобайтными страницами.
Страницы могут использоваться самим ядром, для нужд драйверов (кэширование, например), или для процессов.
Программа или процесс состоит из следующих частей:
Сегмент кода. Может только выполняться, сама программа его не прочитать, не переписать не может! Использовать для этого сегмента swap не нужно, при необходимости код считывается прямо из файла;
Сегмент данных состоит из трех частей:
Константные данные, их тоже можно загружать из файла, так как они не меняются при работе программы;
Инициализированные данные. Участвует в процессе свопинга;
Не инициализированные данные. Так же участвует в свопинге;
Сегмент стека. Так же участвует в свопинге.
Но, обычно, системы делят сегмент данных на две части: инициализированные данные и не инициализированные данные.
Все сегменты разбиваются на страницы. Сегмент кода имеет постоянный размер. Сегмент данных может увеличиваться в сторону больших адресов. Сегмент стека, поскольку растет вниз, увеличивается в сторону уменьшения адресов. Страницы памяти для дополнительных данных или стека выделяются системой по мере необходимости.
Очень интересный момент:
При выполнении программы операционная система делает следующие действия:
Готовит для программы локальную таблицу дескрипторов;
Готовит для программы каталог страниц, все страницы помечаются как не присутствующие в памяти.
Все.
При передаче управления этой программе процессор генерирует исключение по отсутствию страницы, в котором нужная страница загружается из файла или инициализируется.
Еще один интересный момент:
Когда в системе загружается две или более одинаковых программы - нет необходимости для каждой из них выделять место для кодового сегмента, они спокойно могут использовать один код на всех.
Лабораторная работа № 1.
Загрузка операционной системы
Цель работы: Создать загрузочный диск для операционной системы.
Теоретические понятия.
Какие функции выполняет операционная система?
Операционная система должна выполняет следующие функции:
Обеспечивать загрузку пользовательских программ в оперативную память и их исполнение;
Обеспечивать управление памятью. В простейшем случае это указание единственной загруженной программе адреса, на котором заканчивается память, доступная для использования, и начинается память, занятая системой.
Обеспечивать работу с устройствами долговременной памяти, такими как магнитные диски, ленты, оптические диски и т.д.
Предоставлять более или менее стандартизированный доступ к различным периферийным устройствам.
Предоставлять некоторый пользовательский интерфейс.
Что такое загрузочный монитор и каково его предназначение?
Загрузочным монитором называется записанная в ПЗУ программа, которая находиться по тому адресу, по которому процессор передает управление в момент включения питания и производит первичную инициализацию процессора, тестирование памяти и обязательного периферийного оборудования, и, наконец, начинает загрузку системы
В чем отличие загрузочного монитора от консольного монитора?
В отличие от загрузочного монитора, консольный монитор позволяет просматривать содержимое памяти по заданному адресу, записывать туда данные, запускать какую-то область памяти как программу. На консольном мониторе можно даже писать программы, почти с таким же успехом, как на ассемблере.
Приведите определение первичного загрузчика.
Первичным загрузчиком (загрузочный сектор, boot-сектор) - это содержимое нулевого сектора нулевой дорожки диска, с которого производится загрузка. Первичный загрузчик, пользуясь сервисами загрузочного монитора, ищет на диске начало файловой системы своей родной ОС, находит в этой файловой системе файл с определенным именем, считывает его в память и передает этому файлу управление.
Что такое бутстрап?
Бустрап - это последовательное исполнение втягивающих друг друга загрузчиков возрастающей сложности.
Как происходит загрузка операционной системы?
Загрузка операционной системы может происходить по-разному. В простейшем случае, первичный загрузчик, пользуясь сервисами загрузочного монитора, ищет на диске начало файловой системы своей родной ОС, находит в этой файловой системе файл с определенным именем (ядро ОС), считывает его в память и передает этому файлу управление. Если файловая система имеет сложную структуру, то первичный загрузчик не в состоянии самостоятельно произвести загрузку ОС в связи с ограничениями его размера. Поэтому приходится считывать вторичный загрузчик, размер которого может быть намного больше. Из-за большего размера этот загрузчик намного умнее и в состоянии разобраться в структурах файловой системы. В некоторых случаях используются и третичные загрузчики.
Возможен вариант загрузки по сети: ПЗУ, установленное на сетевой карте, посылает в сеть пакет стандартного содержания, который содержит запрос к серверу удаленной загрузки. Этот сервер передает по сети вторичный загрузчик и т.д.
В чем преимущество модульного программирования ОС?
Преимущества модульного программирования ОС заключаются в возможности динамической сборки ядра операционной системы при загрузке, при которой дополнительные модули подгружаются уже после старта самого ядра. Это допускает подгрузку модулей по запросу, при этом подсистемы, нужные только иногда, могут не загрузиться вообще. Даже те модули, которые нужны всегда, могут проинициализироваться, только когда станут нужны, уменьшив тем самым время от начала загрузки до старта некоторых сервисов. Второе преимущество состоит в возможности реконфигурировать систему без перезагрузки, что особенно полезно для систем коллективного пользования. И, наконец, возможность выгрузки модулей ядра иногда (но не всегда, а лишь если поломка не мешает драйверу корректно освободить ресурсы) позволяет корректировать работу отдельных подсистем без перезагрузки всей ОС и пользовательских приложений.
Загрузчик boot. asm
kernel_segequ1000h
org 100h
start:
jmp begin
begin:
mov ax,kernel_seg
mov es,ax
mov bx,100h
call Write
exit:
call far kernel_seg: 0100h
ret
procwrite
mov al,1h
mov dl,0
xor ch,ch
mov cl,2h
mov dh,0
mov ah,02h
int 13h
ret
endp Write
end start
Ядро kernel. asm
code segment para public 'code'
assume cs: code, ds: code, ss: code,es: code
org 100h
main proc
jmp EndData
string db " Operatsionnaea Sisteam studenta Makarova Anatoliea, grupa TI-065"
string_len equ $-string
EndData:
xor ax,ax
mov bh,07h
xor cx,cx
mov dx,0184fh
mov ah,06h
int 10h
mov ah,13h
xor al,al
xor bh,bh
mov cx,string_len
mov bl,06h
mov bp,offset string
mov dl,10
mov dh,10
int 10h
mov ah,00h
int 16h
main endp
code ends
end main
Вывод:
Я научился реализовывать загрузку операционной системы. Изучил основные моменты и правила вызова адресов памяти.
Лабораторная работа № 2.
Меню операционной системы
Цель работы: Создать меню для операционной системы и перехват нажатия клавиш.
Задание: Создать меню для операционной системы, каждое меню содержит свою клавишу, которую надо будет отлавливать программно, выполнить обновление экрана.
Новые добавления:
В процедуре PresKey происходит обработка нажатия клавиш, с последующим выводом сообщения на экран через процедуру print_string.
; - ------------------------------------------- PresKeyPROC Again: mov ah,00h int 16h cmp al,0 jne Again cmp ah,3Bh; Pres F1? je F1 cmp ah,3Ch; Pres F2? je F2 cmp ah,3Dh; Pres F3? je F3 cmp ah,3Eh; Pres F4? je F4 cmp ah,3Fh; Pres F5? je F5 cmp ah,40h; Pres F6? je F6 jmp Again F1: leasi, mes1 callprint_string jmp Again | F2: leasi, mes2 callprint_string jmp Again F3: leasi, mes3 callprint_string jmp Again F4: call clear_screen jmp Again F5: leasi, mes5 callprint_string jmp Again F6: leasi, mes6 callprint_string hlt ret ENDPPresKey |
За вывод сообщения отвечает процедура print_string. Печать происходит по символьное, похожее на teletype.
print_string proc near push ax; store registers... push si; next_char: mov al, [si] cmp al, 0 jz printed inc si | mov ah, 0eh; teletype function. int 10h jmp next_char printed: pop si; re-store registers... pop ax; ret print_string endp |
В ОС предусмотрено обновление экрана, необходима для корректного отображения меню. Предотвращает его смещение.
clear_screen proc near push ax; store registers... push ds; push bx; push cx; push di; mov ax, 40h mov ds, ax; for getting screen parameters. mov ah, 06h; scroll up function id. mov al, 0; scroll all lines! mov bh, 10011111b; attribute for new lines. mov ch, 0; upper row. mov cl, 0; upper col. mov di, 84h; rows on screen - 1,mov dh, [di] ; lower row (byte). mov di, 4ah; columns on screen, mov dl, [di] dec dl; lower col. int 10h ; set cursor position to top ; of the screen: mov bh, 0; current page. mov dl, 0; col. mov dh, 0; row. mov ah, 02 | int 10h pop di; re-store registers... pop cx; pop bx; pop ds; pop ax; mov ah,13h xor al,al xor bx,bx xor dx,dx mov cx,menu_len mov bl,11 mov bp,offset menu mov dl,10 mov dh,18h int 10h mov ah,13h xor al,al xor bh,bh mov cx,string_len mov bl, 19h mov bp,offset string mov dl,10 mov dh,0 int 10h ret clear_screen endp |
Код рабочей программы:
. model small