Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Переход в защищенный режим.Ассемблер

36K
16 декабря 2012 года
kailot2
83 / / 15.12.2012
Вот собственно сабж:
Код:
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)
Только начал изучать защищенный режим, не представляю как это отладить.Код должен выводить символ на экран, символ не выводиться. Ткните пожалуйста носом в ошибки.Локализовать ошибку естес-но не смог поэтому добавил весь исходник
360
16 декабря 2012 года
P*t*
474 / / 15.02.2007
Каким образом это запускается? Из DOS?
Попробуй запускать в эмуляторе qemu и подключаться туда отладчиком: http://jack.kiev.ua/docs/qemu-doc-ru.html#SEC23

P.S А без перехода в защищенный режим что-нибудь работает?
36K
16 декабря 2012 года
kailot2
83 / / 15.12.2012
Цитата: P*t*
Каким образом это запускается? Из DOS?
Попробуй запускать в эмуляторе qemu и подключаться туда отладчиком: http://jack.kiev.ua/docs/qemu-doc-ru.html#SEC23

P.S А без перехода в защищенный режим что-нибудь работает?



Да, запускается из под ДОС, даже не из под ДОС а из под моей ОС , хотя под досом тоже самое. Без перехода в PM не пробовал но работать должно.

360
16 декабря 2012 года
P*t*
474 / / 15.02.2007
В приведенном коде вывод символа находится до перехода в защищенный режим. Это значит, что если он не выводится, то либо защищенный режим не при чем, либо при переходе в защищенный режим управление передается куда-то не в то место и там случайно происходит очистка экрана. Попробуйте закомментировать весь код кроме вывода символа и потом добавлять по одной строке.
36K
16 декабря 2012 года
kailot2
83 / / 15.12.2012
Вот кусочек кода который должен выводить символ уже после перехода в PM:
 
Код:
mov ax,32
mov es,ax
mov ax,010Ah
xor edi,edi
mov [es:edi],word ax
но символ "☺" не выводится, а вывод символа через биосовые инты добавлены как бэ для отладки
360
16 декабря 2012 года
P*t*
474 / / 15.02.2007
Ладно, сейчас полезу в документацию проверять, нет ли ошибок в задании GDT.
А вы все-таки попробуйте запустить это все в qemu и подключиться из gdb.
36K
16 декабря 2012 года
kailot2
83 / / 15.12.2012
qemu скачать возможности нет, коннект фиговый, через USB модем , попробую помучить в BOCHS
36K
16 декабря 2012 года
kailot2
83 / / 15.12.2012
При запуске этой программки BOCHS написал
...
[CPU0 ] cpu hardware reset
...
Что то меня напрягает эта строчка.
Еще до нее есть
[CPU0] is in protect mode (active)
360
16 декабря 2012 года
P*t*
474 / / 15.02.2007
По какому адресу загружается эта программа перед запуском?
Начало сегмента кода в защищенном режиме устанавливается на 0. Значит для корректного перехода на метку continue программа должна находиться по адресу 0x100
Тогда чтобы правильно скопировалась GDT на момент запуска программы в DS должен быть записан 0.
Всё так? Какие начальные значения сегментных регистров?
36K
16 декабря 2012 года
kailot2
83 / / 15.12.2012
Смещение 0x100, сегмент х.з., в ds вроде бы сегмент в котором все это добро, ну то есть это com программа значит cs=ds=es
360
16 декабря 2012 года
P*t*
474 / / 15.02.2007
Здесь обязательно должна быть ошибка - программа не может находиться по адресу 0x100 - этот адрес относится к таблице прерывний.
Вероятно у вас CS = DS = чему-нибудь вроде 0x1000, программа загружается по адресу CS * 16 + org = 0x10000 + 0x100
После перехода в защищенный режим сегмент кода начинается уже не с 0x10000, а с нуля.
Нужный код находится по адресу 0x10000 + continue, а переход происходит на 0x0 + continue
36K
16 декабря 2012 года
kailot2
83 / / 15.12.2012
Цитата:
программа не может находиться по адресу 0x100 - этот адрес относится к таблице прерывний


Она не грузится по адресу 0x100. Она грузиться где то по 01000h:0100h, 02000h:0100h и т.д., в ДОС я вообще х.з. куда он ее грузит.

36K
16 декабря 2012 года
kailot2
83 / / 15.12.2012
Цитата:
Нужный код находится по адресу 0x10000 + continue, а переход происходит на 0x0 + continue


А вот это походу точно.Завтра проверю, сейчас спать...

36K
16 декабря 2012 года
kailot2
83 / / 15.12.2012
Код:
;Сегмент кода
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
Кажется мне что после mov bx,start BX нужно поделить на 16 что бы получить кол-во параграфов, и уже потом прибавлять к сегменту
360
16 декабря 2012 года
P*t*
474 / / 15.02.2007
Прибавлять start не стоит. Тогда получится не адрес сегмента, а адрес точки входа (который на 0х100 больше адреса сегмента)
36K
17 декабря 2012 года
kailot2
83 / / 15.12.2012
Блин... в PM адреса данных и кода в дескрипторе могут совпадать. А если вот так заполнять GDT:

 
Код:
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
А что в этом случае в GDTR загружать?
36K
17 декабря 2012 года
kailot2
83 / / 15.12.2012
Нашел годный пример
Код:
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
Как мне заточить его под свои цели? ну в начале оrg 0x100 понятно, а вот как быть с Сегментом? в примере программа заранее "знает" по какому адресу ее грузят.
36K
17 декабря 2012 года
kailot2
83 / / 15.12.2012
Как конкретно переделать вот эти места если я заранее не знаю по какому адресу грузится программа:
...
jmp 1000h:r_start
r_start:
mov ax,1000h;перенастраиваем регистры
...
dd GDT+10000h
...
virtual ;теперь, фактически, забиваем пространство до конца сегмента
rb 10000h-$;
end virtual
...
org $+10000h
...
36K
17 декабря 2012 года
kailot2
83 / / 15.12.2012
Пока что извратился и написал загрузчик который грузить бинарь по адресу 0x5000:0 и передает ему управление, моленько переделал исходник что выше и увидел наконец то
"Welcome to PM, dude"
252
17 декабря 2012 года
koderAlex
1.4K / / 07.09.2005
"Как конкретно переделать вот эти места если я заранее не знаю по какому адресу грузится программа" - зато регистр CS знает :)
36K
17 декабря 2012 года
kailot2
83 / / 15.12.2012
Цитата: koderAlex
"Как конкретно переделать вот эти места если я заранее не знаю по какому адресу грузится программа" - зато регистр CS знает :)


Гы =) я знаю что регистр CS знает , но в исходнике выше сегмент указан непосредственно.
вот например здесь org $+10000h. Я думаю ассемблер не оценит org $+CS =)

360
17 декабря 2012 года
P*t*
474 / / 15.02.2007
Исправь в своем коде фрагмент
 
Код:
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
на

 
Код:
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
Не нужно прибавлять метку старт так как continue отсчитывается не от start, continue отсчитывается от CS*16
36K
17 декабря 2012 года
kailot2
83 / / 15.12.2012
исправил, все равно не р.б. =(
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог