Вот набросал код переводящий процессор в PM, пытаюсь реализовать страничную адресацию. Помогите, с проецировать физический адрес видео буфера 0xB8000 в виртуальный.
Код:
format Binary as "bin"
use16 ; 16-ти битный код
SEG_P equ 1000000000000000b ; Бит присутствия
SEG_DPL_0 equ 0000000000000000b ; Уровень привелегий - 0 (наивысший)
SEG_DPL_1 equ 0010000000000000b ; Уровень привелегий - 1
SEG_DPL_2 equ 0100000000000000b ; Уровень привелегий - 2
SEG_DPL_3 equ 0110000000000000b ; Уровень привелегий - 3 (низший)
SEG_DATA_R equ 0001000000000000b ; Сегмент данных, только считывание
SEG_DATA_RW equ 0001001000000000b ; Сегмент данных, считывание и запись
SEG_STACK_R equ 0001010000000000b ; Сегмент стека, только считывание
SEG_STACK_RW equ 0001011000000000b ; Сегмент стека, считывание и запись
SEG_CODE_X equ 0001100000000000b ; Сегмент кода, только выполнение
SEG_CODE_RX equ 0001101000000000b ; Сегмент кода, считывание и выполнение
SEG_P_CODE_X equ 0001110000000000b ; Подчиненный сегмент кода, только выполнение
SEG_P_CODE_RW equ 0001111000000000b ; Подчиненный сегмент кода, только выполнение и считывание
SEG_G equ 0000000010000000b ; Гранулярность. 1 - 4КБ, 0 - 1 байт
SEG_32 equ 0000000001000000b ; Битность кода в сегменте. 1 - 32 бита, 0 - 16 бит
SL_CODE equ 08 ; Селектор сегмента кода (1-ый дескриптор в GDT)
SL_STACK equ 16 ; Селектор сегмента стека (2-ый дескриптор в GDT)
SL_DATA equ 24 ; Селектор сегмента данных (3-ий дескриптор в GDT)
SL_VIDEO equ 32 ; Селектор сегмента видео-памяти (4-ий дескриптор в GDT)
; Описание регистра CR3. Старшие 20 бит это старшие разряды физического базового адреса каталога страниц,
; по скольку страница должна быть выровняна на 4 кб, младшие 12 разрядов считаются равными 0.
; Затем с лева на право, 7 бит резерв, 1 бит PCD (Запрет кэша уровня страниц), 1 бит PWT (Прозрачная запись в таблицы страниц).
; И младшие 0-2 биты сам не знаю что... Получаем 0b00000000000000000000 0000000 00 000
CR3_REG equ 00000000000000000001000000000000b ; Адрес каталога страниц 0x1000, атрибуты 0
; Описание первого дескриптора таблиц в каталоге таблиц страниц, с лева на право
; 20 бит - начальный физический адрес таблицы страниц PTE
; 3 бита - Не используются, Можно задействовать в личных целях
; 1 бит - Global page. В каталоге таблиц страниц бит игнорируется.
; 1 бит - Page size. Бит задает размер страниц в каталоге.
; 1 бит - Reserved
; 1 бит - Accessed. Этот бит показывает был ли произведен доступ к каталогу
; 1 бит - Cache disable. Если бит выставлен, то кеширование страниц каталога запрещено.
; 1 бит - Write-throung. Включение, отключение сквозной записи
; 1 бит - User/Supervisor. Бит разрешает пользоваться страницами каталога обычным приложениям.
; 1 бит - Read/Write. Этот бит показывает, доступны ли данные в каталоге страницы для записи.
; 1 бит - Present. Если 0, то каталог не отображен на физическую память.
PDE_0 equ 00000000000000000010000000000001b ; Адрес таблицы страниц 0x2000, атрибуты 0
; Описание первого дескриптора страницы в каталоге страниц, с лева на право
; 20 бит - начальный физический адрес страницы
; 3 бита - Не используются, Можно задействовать в личных целях
; 1 бит - Global page. Когда бит выставлен, страница является глобальной.
; 1 бит - Page size. Бит задает размер страницы
; 1 бит - Dirty. Тоже самое что и бит A но устанавливается всякий раз при записи на страницу
; 1 бит - Accessed. Этот бит показывает был ли произведен доступ к странице
; 1 бит - Cache disable. Если бит выставлен, то кеширование страницы запрещено.
; 1 бит - Write-throung. Включение, отключение сквозной записи
; 1 бит - User/Supervisor. Бит разрешает пользоваться страницей обычным приложениям.
; 1 бит - Read/Write. Этот бит показывает, доступны ли данные в странице для записи.
; 1 бит - Present. Если 0, то страница не отображена на физическую память.
PTE_0 equ 00000000000000001011000000000001b
; Используем смещение для расчёта меток программы
org 0x7C00
jmp start
; Макрос добавления дескриптора в глобальную таблицу дескрипторов
; gdt_address - Адрес таблицы
; des_number - Номер дескриптора
; seg_base - Адрес базы сегмента
; seg_size - Размер сегмента
; attr - Бит присутствия, уровень привелегий, тип сегмента, гранулярность,
; разрядность кода в сегменте,
macro m_add_desc_to_gdt gdt_address, des_number, seg_base, seg_size, attr
{
pushad
mov esi,gdt_address
mov edi,des_number
mov ebx,seg_base ; 32 битный адрес базы сегмента
mov edx,seg_size ; 20 битный размер сегмента
mov cx,attr
call add_desc_to_gdt
popad
}
; Подпрограмма добавления дескриптора в глобальную таблицу дескрипторов
add_desc_to_gdt:
mov word [esi + 8 * edi+2], bx ; base_l. Записываем младшую часть базы, 2 байта
shr ebx, 16 ; Сдвигаем среднюю и старшую часть базы в регистр AX
mov byte [esi + 8 * edi+4], bl ; base_m. Записываем среднюю часть базы, 1 байт
mov byte [esi + 8 * edi+7], bh ; base_h. Записываем старшую часть базы, 1 байт
dec edx
mov word [esi + 8 * edi], dx ; size_l Записываем младшую часть размера, 2 байта
shl edx, 12 ; Стираем 12 бит в старшей части регистра EAX,
; так как мы используем только 4 из 16 бит старшей части. Остольное должно быть = 0,
shr edx, 12 ; что бы при сложении размера с атрибутами не было неверных данных
shr edx, 16 ; Сдвигаем старшую часть размера в AX, теперь в al младшие 4 бита это старшая часть размера,
; остальные биты после стирания = 0
add dx, cx ; Добавим атрибуты к адресу (первый байт атрибутов содержит P,DPL,S,T,U. Второй быйт G,DB)
rol dx, 8 ; Меняем местами байты, чтобы в начале записалсь P,DPL,S,T,U а затем G,DB
mov word [esi + 8 * edi+5], dx ; Запишем 2 байта атрибутов
ret
disk_id db ? ; диск с которого произведена загрузка
start:
; Инициализация сегментных регистров
cli ; Запретить прерывания для смены адресов в сегментных регистрах
; cs=0
xor ax, ax ; ах = 0
mov ss, ax ; ss = 0 (Сегмент стека)
mov sp,0x7C00 ; Указатель стека
push ax
pop es ; es = 0 (Дополнительный сегмент данных)
push ax
pop ds ; ds = 0 (Сегмент данных)
sti ; Разрешить прерывания (после изменения адресов)
mov [disk_id],dl
; Очистка экрана
mov ax,02h ; Очищаем экран - функция 02h прерывания 10h
int 10h
; Открыть адресную линию A20 (чтобы была доступна вся память).
in al,0x92 ; Читаем содержимое порта 0х92
or al,2 ; Устанавливаем второй бит
out 0x92,al ; Записываем обратно в порт 0х92
; Заполняем таблицу GDT
; GDT_address, (DW)des_number, (DD)seg_base, (20bit)seg_size, (DW) attr - present,seg_dpl,seg_type,seg_granular,seg_bitDepth
m_add_desc_to_gdt 0x7E00, 0, 0, 0, 0 ; Пустой
m_add_desc_to_gdt 0x7E00, 1, 0, 0FFFFFh, SEG_P+SEG_CODE_X+SEG_G+SEG_32 ; Дескриптор кода
m_add_desc_to_gdt 0x7E00, 2, 0x7C00, 512, SEG_P+SEG_STACK_RW+SEG_32 ; Дескриптор стека
m_add_desc_to_gdt 0x7E00, 3, 0, 0FFFFFh, SEG_P+SEG_DATA_RW+SEG_G+SEG_32 ; Дескриптор данных
m_add_desc_to_gdt 0x7E00, 4, 0B8000h, 4096, SEG_P+SEG_DATA_RW+SEG_G+SEG_32 ; Дескриптор видеопамяти
; Заняли 40 байт
lgdt [gdtr] ; загружаем регистр GDTR.
; Запрет всех прерываний
cli ; Запретить аппаратные прерывания
; запрет NMI
in al,70h
or al,80h
out 70h,al
; Переключаемся в защищенный режим.
mov eax,cr0
or al,1 ; устанавливаем 0-вой бит
mov cr0,eax ; включаем PM
; Перейдём на 32-битный код
jmp fword SL_CODE:start32
;Описание глобальной таблицы дескрипторов
gdtr:
.size dw (5*8)-1 ; Размер таблицы в байтах. 5 дескрипторов по 8 байт, минус один байт
.addres dd 0x7E00 ; Физический адрес таблицы, сразу после загрузчика
; ====================================================================================================================================
use32
start32:
; Инициализируем сегментные регистры, помещая в них селекторы
mov ax, SL_DATA ; Сегмент данных
mov ds, ax ; ds = SELECTOR_DATA
mov fs, ax ; fs = SELECTOR_DATA
mov ax, SL_STACK ; сегмент стека
mov ss, ax ; ss = SELECTOR_STACK
mov esp, 0x7C00 ; Стек
mov ax,SL_VIDEO
mov gs,ax
mov dword [0x1000],PDE_0
mov dword [0x2000],PTE_0
mov eax,CR3_REG
mov cr3,eax
jmp page
page:
mov esi,string ; Вывести сообщение из PM
call print
jmp $
; ESI - адрес строки
print:
pushad
xor ebx,ebx
mov ah,07h
puts:
mov al,[esi+ebx]
mov [0xB8000+(ebx*2)],ax
inc ebx
test al,al
jnz puts
popad
ret
string db "Protected Mode - Enable", 0
; =====================================================================================================================================
;-----Заполнитель-----
; Заполняем оставшееся место до 510 байт нулями
times 510 - ($ - $$) db 0 ; $ = адрес текущей инструкции
; $$ = адрес 1-й инструкции
;Последние два байти 511-тый и 512-тый
dw 0xAA55 ; сигнатура загрузочного сектора