Переход в защищенный режим.Ассемблер
Код:
org 0100h
struc descr Limit,Base_1,Base_2,Atr,Lim_atr,Base_3
{
.Limit dw 0
.Base_1 dw 0
.Base_2 db 0
.Atr db 0
.Lim_atr db 0
.Base_3 db 0
}
start:
mov ax,03h
int 10h
push ax
mov ah,0eh
mov al,'1'
int 10h
pop ax
mov ax,cs
shl eax,4
xor ebx,ebx
mov bx,@data
add eax,ebx
mov ebp,eax
mov bx,[gdt_size-1]
mov [higdtr],bx ;В старшем слове GDTR лимит GDT
mov [lowgdtr],eax ;В младшем двойном слове база GDT
;EBP = физический адрес сегмента данных
;Заполним таблицу GDT
;Сегмент данных
xor eax,eax
mov eax,ebp
mov [gdt_data.Base_1],ax
shr eax,16
mov [gdt_data.Base_2],byte al
;Сегмент кода
xor eax,eax
xor ebx,ebx
mov ax,cs
shl eax,4
mov bx,start
add eax,ebx
;В ЕАХ физ.адресс сегмента кода
mov [gdt_code.Base_1],ax
shr eax,16
mov [gdt_code.Base_2],al
;Сегмент стека
xor eax,eax
xor ebx,ebx
mov ax,cs
mov bx,_Stack
shl eax,4
add eax,ebx
mov [gdt_stack.Base_1],ax
shr eax,16
mov [gdt_stack.Base_2],al
push ax
mov ah,0eh
mov al,'2'
int 10h
pop ax
;GDT заполнена , можно нырять в PM
lgdt [_GDTR]
cli
mov eax,cr0
or eax,1
mov cr0,eax
db 0EAh
dw continue
dw 8
use32
align 16
continue:
mov ax,32
mov es,ax
mov ax,010Ah
xor edi,edi
mov [es:edi],word ax
jmp $
ret
code_size dw $-start
align 16
@data:
GDT:
gdt_null descr <0,0,0,0,0,0> ;Нулевой дескриптор
gdt_code descr <[code_size]-1,0,0,98h,0,0> ;Селектор 8 сегмент кода
gdt_data descr <[data_size]-1,0,0,92h,0,0> ;Селектор 16 сегмент данных
gdt_stack descr <1FFh,0,0,92h,0,0>
gdt_screen descr <3999,8000h,0bh,92h,0,0> ;Селектор 32 видеопамять
gdt_size = $-gdt_null
symbol dw 010Ah
msg db 27,'[31;42m RealMode',26,'[0m$'
align 16
_GDTR:
higdtr: dw ?
lowgdtr dd ?
data_size = $-gdt_null
align 16
_Stack:
db 200h dup (0)
struc descr Limit,Base_1,Base_2,Atr,Lim_atr,Base_3
{
.Limit dw 0
.Base_1 dw 0
.Base_2 db 0
.Atr db 0
.Lim_atr db 0
.Base_3 db 0
}
start:
mov ax,03h
int 10h
push ax
mov ah,0eh
mov al,'1'
int 10h
pop ax
mov ax,cs
shl eax,4
xor ebx,ebx
mov bx,@data
add eax,ebx
mov ebp,eax
mov bx,[gdt_size-1]
mov [higdtr],bx ;В старшем слове GDTR лимит GDT
mov [lowgdtr],eax ;В младшем двойном слове база GDT
;EBP = физический адрес сегмента данных
;Заполним таблицу GDT
;Сегмент данных
xor eax,eax
mov eax,ebp
mov [gdt_data.Base_1],ax
shr eax,16
mov [gdt_data.Base_2],byte al
;Сегмент кода
xor eax,eax
xor ebx,ebx
mov ax,cs
shl eax,4
mov bx,start
add eax,ebx
;В ЕАХ физ.адресс сегмента кода
mov [gdt_code.Base_1],ax
shr eax,16
mov [gdt_code.Base_2],al
;Сегмент стека
xor eax,eax
xor ebx,ebx
mov ax,cs
mov bx,_Stack
shl eax,4
add eax,ebx
mov [gdt_stack.Base_1],ax
shr eax,16
mov [gdt_stack.Base_2],al
push ax
mov ah,0eh
mov al,'2'
int 10h
pop ax
;GDT заполнена , можно нырять в PM
lgdt [_GDTR]
cli
mov eax,cr0
or eax,1
mov cr0,eax
db 0EAh
dw continue
dw 8
use32
align 16
continue:
mov ax,32
mov es,ax
mov ax,010Ah
xor edi,edi
mov [es:edi],word ax
jmp $
ret
code_size dw $-start
align 16
@data:
GDT:
gdt_null descr <0,0,0,0,0,0> ;Нулевой дескриптор
gdt_code descr <[code_size]-1,0,0,98h,0,0> ;Селектор 8 сегмент кода
gdt_data descr <[data_size]-1,0,0,92h,0,0> ;Селектор 16 сегмент данных
gdt_stack descr <1FFh,0,0,92h,0,0>
gdt_screen descr <3999,8000h,0bh,92h,0,0> ;Селектор 32 видеопамять
gdt_size = $-gdt_null
symbol dw 010Ah
msg db 27,'[31;42m RealMode',26,'[0m$'
align 16
_GDTR:
higdtr: dw ?
lowgdtr dd ?
data_size = $-gdt_null
align 16
_Stack:
db 200h dup (0)
Попробуй запускать в эмуляторе qemu и подключаться туда отладчиком: http://jack.kiev.ua/docs/qemu-doc-ru.html#SEC23
P.S А без перехода в защищенный режим что-нибудь работает?
Цитата: P*t*
Каким образом это запускается? Из DOS?
Попробуй запускать в эмуляторе qemu и подключаться туда отладчиком: http://jack.kiev.ua/docs/qemu-doc-ru.html#SEC23
P.S А без перехода в защищенный режим что-нибудь работает?
Попробуй запускать в эмуляторе qemu и подключаться туда отладчиком: http://jack.kiev.ua/docs/qemu-doc-ru.html#SEC23
P.S А без перехода в защищенный режим что-нибудь работает?
Да, запускается из под ДОС, даже не из под ДОС а из под моей ОС , хотя под досом тоже самое. Без перехода в PM не пробовал но работать должно.
В приведенном коде вывод символа находится до перехода в защищенный режим. Это значит, что если он не выводится, то либо защищенный режим не при чем, либо при переходе в защищенный режим управление передается куда-то не в то место и там случайно происходит очистка экрана. Попробуйте закомментировать весь код кроме вывода символа и потом добавлять по одной строке.
Код:
mov ax,32
mov es,ax
mov ax,010Ah
xor edi,edi
mov [es:edi],word ax
mov es,ax
mov ax,010Ah
xor edi,edi
mov [es:edi],word ax
А вы все-таки попробуйте запустить это все в qemu и подключиться из gdb.
qemu скачать возможности нет, коннект фиговый, через USB модем , попробую помучить в BOCHS
...
[CPU0 ] cpu hardware reset
...
Что то меня напрягает эта строчка.
Еще до нее есть
[CPU0] is in protect mode (active)
Начало сегмента кода в защищенном режиме устанавливается на 0. Значит для корректного перехода на метку continue программа должна находиться по адресу 0x100
Тогда чтобы правильно скопировалась GDT на момент запуска программы в DS должен быть записан 0.
Всё так? Какие начальные значения сегментных регистров?
Смещение 0x100, сегмент х.з., в ds вроде бы сегмент в котором все это добро, ну то есть это com программа значит cs=ds=es
Вероятно у вас CS = DS = чему-нибудь вроде 0x1000, программа загружается по адресу CS * 16 + org = 0x10000 + 0x100
После перехода в защищенный режим сегмент кода начинается уже не с 0x10000, а с нуля.
Нужный код находится по адресу 0x10000 + continue, а переход происходит на 0x0 + continue
Она не грузится по адресу 0x100. Она грузиться где то по 01000h:0100h, 02000h:0100h и т.д., в ДОС я вообще х.з. куда он ее грузит.
А вот это походу точно.Завтра проверю, сейчас спать...
Код:
;Сегмент кода
xor eax,eax
xor ebx,ebx
mov ax,cs
shl eax,4
mov bx,start
add eax,ebx
;В ЕАХ физ.адресс сегмента кода
mov [gdt_code.Base_1],ax
shr eax,16
mov [gdt_code.Base_2],al
xor eax,eax
xor ebx,ebx
mov ax,cs
shl eax,4
mov bx,start
add eax,ebx
;В ЕАХ физ.адресс сегмента кода
mov [gdt_code.Base_1],ax
shr eax,16
mov [gdt_code.Base_2],al
Прибавлять start не стоит. Тогда получится не адрес сегмента, а адрес точки входа (который на 0х100 больше адреса сегмента)
Код:
mov ax,cs
shl eax,4
mov [gdt_code.Base_1],ax
mov [gdt_data.Base_1],ax
shr eax,16
mov [gdt_code.Base_2],ax
mov [gdt_code.Base_2],ax
shl eax,4
mov [gdt_code.Base_1],ax
mov [gdt_data.Base_1],ax
shr eax,16
mov [gdt_code.Base_2],ax
mov [gdt_code.Base_2],ax
Код:
format binary
xor ax,ax
cli ;реинициализируем сегментные регистры
mov ss,ax
xor sp,sp
sti
mov ax,3
int 10h
jmp 1000h:r_start
r_start:
mov ax,1000h;перенастраиваем регистры
mov ds,ax
mov es,ax
in al, 0x92;включаем A20
or al, 2
out 0x92, al
cli ;запрещаем прерывания
mov al,8Fh;запрещаем NMI
out 70h,al
in al,71h
lgdt fword [GDTR];загружаем регистр GDTR
mov eax,cr0
or al,1;устанавливаем 0-вой бит
mov cr0,eax;включаем PM
jmp fword 08h:Startup32; прыгаем в PM
align 8 ;процессор быстрее обращается с выравненной табличкой
GDT:
dq 0 ;пустой
db 0FFh,0FFh,0,0,0,9Ah,0CFh,0 ;код
db 0FFh,0FFh,0,0,0,92h,0CFh,0;данные
db 0FFh,0FFh,0,80h,0Bh,92h,40h,0 ;видеосегмент
label GDT_SIZE at $-GDT
GDTR:
dw GDT_SIZE-1
dd GDT+10000h
; нужно записать 32-битный адрес. Сейчас мы находимся в сегменте 1000h, база которого 1000h*10h (по ;физическому адресу) => физический адрес GDTR (метки!) = 10000h (физический адрес базы сегмента)+offset
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
xor ax,ax
cli ;реинициализируем сегментные регистры
mov ss,ax
xor sp,sp
sti
mov ax,3
int 10h
jmp 1000h:r_start
r_start:
mov ax,1000h;перенастраиваем регистры
mov ds,ax
mov es,ax
in al, 0x92;включаем A20
or al, 2
out 0x92, al
cli ;запрещаем прерывания
mov al,8Fh;запрещаем NMI
out 70h,al
in al,71h
lgdt fword [GDTR];загружаем регистр GDTR
mov eax,cr0
or al,1;устанавливаем 0-вой бит
mov cr0,eax;включаем PM
jmp fword 08h:Startup32; прыгаем в PM
align 8 ;процессор быстрее обращается с выравненной табличкой
GDT:
dq 0 ;пустой
db 0FFh,0FFh,0,0,0,9Ah,0CFh,0 ;код
db 0FFh,0FFh,0,0,0,92h,0CFh,0;данные
db 0FFh,0FFh,0,80h,0Bh,92h,40h,0 ;видеосегмент
label GDT_SIZE at $-GDT
GDTR:
dw GDT_SIZE-1
dd GDT+10000h
; нужно записать 32-битный адрес. Сейчас мы находимся в сегменте 1000h, база которого 1000h*10h (по ;физическому адресу) => физический адрес GDTR (метки!) = 10000h (физический адрес базы сегмента)+offset
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
...
jmp 1000h:r_start
r_start:
mov ax,1000h;перенастраиваем регистры
...
dd GDT+10000h
...
virtual ;теперь, фактически, забиваем пространство до конца сегмента
rb 10000h-$;
end virtual
...
org $+10000h
...
"Welcome to PM, dude"
"Как конкретно переделать вот эти места если я заранее не знаю по какому адресу грузится программа" - зато регистр CS знает :)
Цитата: koderAlex
"Как конкретно переделать вот эти места если я заранее не знаю по какому адресу грузится программа" - зато регистр CS знает :)
Гы =) я знаю что регистр CS знает , но в исходнике выше сегмент указан непосредственно.
вот например здесь org $+10000h. Я думаю ассемблер не оценит org $+CS =)
Код:
mov ax,cs
shl eax,4
mov bx,start
add eax,ebx
;В ЕАХ физ.адресс сегмента кода
mov [gdt_code.Base_1],ax
shr eax,16
mov [gdt_code.Base_2],al
shl eax,4
mov bx,start
add eax,ebx
;В ЕАХ физ.адресс сегмента кода
mov [gdt_code.Base_1],ax
shr eax,16
mov [gdt_code.Base_2],al
Код:
mov ax,cs
shl eax,4
; mov bx,start
; add eax,ebx
;В ЕАХ физ.адресс сегмента кода
mov [gdt_code.Base_1],ax
shr eax,16
mov [gdt_code.Base_2],al
shl eax,4
; mov bx,start
; add eax,ebx
;В ЕАХ физ.адресс сегмента кода
mov [gdt_code.Base_1],ax
shr eax,16
mov [gdt_code.Base_2],al
исправил, все равно не р.б. =(