Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Как создать свою операционную систему.docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
33 Кб
Скачать
☆

Virtual ;теперь, фактически, забиваем пространство до конца сегмента

rb 10000h-$;

end virtual

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;PM32 Entry;;;;;;;;;;;;;;;;;;;

use32

org $+10000h;вот для чего: в PM мы работаем с Flat-сегментами, и если мы оставим код ;для PM перед org’ом, то ;внутрисегментный адрес не будет совпадать с Flat адресом. Так вот.

Startup32: ;точка входа в PM

mov ax,10h ;здесь пихаем селекторы. Зачастую (! не забываем про порядковый номер в

mov es,ax ;таблице) селектор сегмент кода - 08h. данных - 10h, видеосегмент - 18h

mov ds,ax

mov fs,ax

mov ss,ax

mov esp,10000h;стек

mov ax,18h

mov gs,ax

mov esi,hi_string ;покажем, что мы удачно перешли

call print

jmp $

;ESI - адрес строки

print:

pushad

xor ebx,ebx

mov ah,07h;атрибут

puts:

mov al,[esi+ebx]

mov [gs:(ebx*2)],ax

inc ebx

test al,al

jnz puts

popad

ret

hi_string db ‘Welcome to PM, dude’,0

Что мы сделали? Загрузчик нас успешно загрузил по адресу 1000h:0, откуда мы и продолжили выполнение. Сначала включили А20, запретили все прерывания, загрузили в GDTR подходящее значение, прыгнули на метку входа. Замечу, что прыгали мы на

jmp fword 08h:Startup32

Т.е 08h — селектор дескриптора кода. Привыкайте.

Теперь как сие чудо запустить. Лично я пользуюсь WinImage и VirtualBox. Запихиваем загрузчик в бутсектор дискеты и кладём .bin’овский файл в корень. Сохраняем в .vfd, прописываем путь к образу дискеты в свойствах виртуальной машины, запускаем и видим результат.

Введём в нашу наработку paging, разберёмся с прерываниями и их видами. Напишем несколько функций, добавим сие в код из предыдущего поста.

1) Paging.

Все, наверно, уже покопались в манах и знают, что за лепота этот paging. Вырываемся за пределы 1 Мб и можем адресовать все 4 гигабайта оперативки. Но зачем нам в нашей скромной поделке 4 Гб (тем более что не у всех есть столько RAM’а). Нам вполне будет достаточно 32Мб (ну, это тоже очень много, но давайте помечтаем). Итак, будем использовать 4Кб’айтные страницы. Так, теперь считаем – 1024 страницы описывают 4Мб. Нам, значит, нужно всего-то 1024*8 страниц. Иными словами нужно завести 8 таблиц и 1 каталог. Ещё, для удобства, страницы будут тождественными т.е логический и физический адреса совпадают. Теперь, давайте напишем функцию, которая сформирует всё необходимое.

set_pages:

.set_cat:

mov edi,100000h;базовый адрес директории

mov eax,101007h;базовый адрес таблицы страниц и флаги

mov cx,8 ;8*4Мб=32Мб

.fill_cat_usef: ;опишем таблицы страниц

stosd

add eax,1000h

loop .fill_cat_usef

mov cx,1016 ;а остальное забьём нулями

xor eax,eax

rep stosd

mov eax,00000007h

mov ecx,1024*8;32Mb

.fill_page_table: ;теперь опишем страницы

stosd

add eax,1000h

loop .fill_page_table

;End;

mov eax,00100000h;1 Mb;и установим базовый адрес первого каталога в cr3

mov cr3,eax

mov eax,cr0

or eax,80000000h

mov cr0,eax

ret

Возможно у вас возникнет вопрос, зачем же забивать нулями другие каталоги? А не забываем, что располагать таблицы, как и каталоги, можно по адресам, кратным 1000h.

2) Interrupts.

И с прерываниями PM преподносит сюрпризы: нет больше 4-ых байтных векторов прерываний, как в RM. На их место пришли Interrupt Gates (для нас сейчас важны именно они), Trap Gates, Task Gates – 64-битные структуры, находящиеся в IDT. И структура такова:

Здесь назначение полей ясно (тем более, что некоторые из них встречались нам ещё в segment descriptor’ах). Мы пока рассмотрим только Interrupt Gates. IDT нужно составить до перехода в PM, загрузить размер и смещение в регистр IDTR (его структура аналогична структуре GDTR) командой lidt. Кстати, IDT – сегмент (скажем так, антипод GDT, которая просто в линейном адресном пространстве находится) т.е она располагается в определённом сегменте. Например, если вы до перехода в PM описали, к примеру, 4Кб памяти, а располагаете IDT за этими пределами, и разрешите прерывания после перехода в PM, то всё рухнет.

Еще пара замечаний: Intel зарезервировала прерывания 0-31. Туда нужно класть обработчики для этих exception’ов. Среди них ошибка деления на 0 (#DE), исключение общей защиты #GP и другие не менее весёлые вещи. Поэтому нужно базовый адрес прерываний сместить т.е сделать так, чтобы IRQ0 занимало 32 позицию и.т.д. Сразу оговорюсь, что использовать будем старую-добрую микросхему i8259a. Конечно, можно использовать и APIC – Advanced Programmable Interrupt Controller (кстати, его нужно ручками включить), но нам просто не придётся пользоваться преимуществами такового (расширение кол-ва аппаратных прерываний, приспособленность под многопроцессорность и.т.д). Надеюсь, все помнят, что такое ICW (Initialization Control Word) и OCW (Operation Control Word)? Давайте повторим, что для чего используется (структуру приводить не буду):

ICW:

1) Определение особенности последовательности приказов.

2) Определение базового адреса (вот о чём я говорил).

3) Связь контроллеров.

4) Дополнительные особенности обработки прерываний.

OCW:

1) Управление регистром масок IMR.

2) Управление приоритетом.

3) Общее управление контроллером.

Процедура инициализации выглядит следующим образом:

Init_PIC:

mov al,11h;ICW1 – прерывание по перепаду сигнала, схемы подключены каскадно

out 20h,al;Мастеру

out 0A0h,al;Слэйву

mov al,20h;ICW2;базовый адрес (он абстрактный! Не путайте с адресом в RAM)

out 21h,al;Мастеру одно значение

mov al,28h;Слэйву другое

out 0A1h,al

mov al,04h;ICW3 – слэйв к входу IRQ2 подключён

out 21h,al

mov al,02h

out 0A1h,al

mov al,11h;ICW4 – сбрасываем флаг наличия прерывания вручную и используем камень Pentium

out 21h,al

mov al,01h

out 0A1h,al

ret

Теперь построим IDT:

IDT:

dd 0,0; 0

dd 0,0 ; 1

dd 0,0

dd 0,0 ; 3

;…. Убрал для краткости!

dd 0,0 ; 12

dw GP_handler and 0FFFFh,08h, 1000111000000000b, GP_handler shr 16 ; 13 #GP

dd 0,0 ; 14

;…. Я просто для краткости так написал. Забейте хоть тем же dup’ом это свободное место,

;чтоб не писать наскучившее dd 0,0

dd 0,0 ; 30

dd 0,0 ; 31;Здесь заканчиваются зарезервированные Intel номера ;gate’ов

dw timer and 0FFFFh, 08h, 1000111000000000b, timer shr 16 ; IRQ 0 - системный таймер

dw keyboard and 0FFFFh , 08h, 1000111000000000b, keyboard shr 16 ; IRQ 1 - клавиатура - ;предлагаю вам самим написать обработчик

dd 0,0;IRQ2

dd 0,0;IRQ3

dd 0,0;IRQ4

dd 0,0;IRQ5

dd 0,0;IRQ6

label IDT_size at $-IDT