; собственно, загрузка регистра GDTR:
lgdt fword ptr GDTR
Простейшее использование видеопамяти
Так же я смотрел здесь, почему то тоже строку не выводит. (У меня сделано аналогично).
ПОМОГИТЕ! ВЧЁМ ОШИБКА ИСХОДНОГО КОДА.?
0xb8000+(y*160)+x*2
у меня все работает
Ошибка оказалась не в выводе строки, а ещё перед очисткой экрана.
VMware ругается на стек. Это мой Boot-сектор глючит.
Проц делает RESET на строке
Код:
переменая GDTR:
Код:
GDTR dw GDT_size-1 ; 16-битнvй лимит GDT
dd ? ; здесь будет 32-битнvй линейнvй адрес GDT
dd ? ; здесь будет 32-битнvй линейнvй адрес GDT
Интересно почему RESET?
Так процессор реагирует на критические ошибки...
Это понятно, хотел бы я знать в чём она...
Виртуальная машина ругается на стек
(*** Virtual machine kernel stack fault (hardware reset) ***
The virtual machine just suffered a stack fault in kernel mode. On a real computer, ...)
, стек инициалозирую вот так:
Код:
mov ax,3000h
mov ss,ax
mov ss,ax
Может чего в инициализатции поправить:confused:
Код:
RM_CODE segment para public 'CODE' use16
@@start:
assume CS:RM_CODE,SS:RM_STACK
mov ax,3000h
mov ss,ax
; очистка экрана:
mov AX,3
int 10h
; для 32-х битной адресации:
in AL,92h
or AL,2
out 92h,AL
; вvчисляем линейнvй адрес метки ENTRY_POINT (точка входа в защищеннvй режим):
xor EAX,EAX ; обнуляем регистра EAX
mov AX,PM_CODE ; AX = номер сегмента PM_CODE
shl EAX,4 ; EAX = линейнvй адрес PM_CODE
add EAX,offset ENTRY_POINT ; EAX = линейнvй адрес ENTRY_POINT
mov dword ptr ENTRY_OFF,EAX ; сохраняем его в переменной
; теперь надо вvчислить линейнvй адрес GDT (для загрузки регистра GDTR):
xor EAX,EAX
mov AX,RM_CODE ; AX = номер сегмента RM_CODE
shl EAX,4 ; EAX = линейнvй адрес RM_CODE
add AX,offset GDT ; теперь EAX = линейнvй адрес GDT
; линейнvй адрес GDT кладем в заранее подготовленнуі переменнуі:
mov dword ptr GDTR+2,EAX
; собственно, загрузка регистра GDTR:
lgdt fword ptr GDTR ;ЗДЕСЬ БАГ!!!
; запрет маскируемvх прерvваний:
cli
; запрет немаскируемvх прерvваний:
in AL,70h
or AL,80h
out 70h,AL
; переключение в защищеннvй режим:
mov EAX,CR0
or AL,1
mov CR0,EAX
; загрузить новvй селектор в регистр CS
db 66h ; префикс изменения разрядности операнда
db 0EAh ; опкод командv JMP FAR
ENTRY_OFF dd ? ; 32-битное смеение
dw 00001000b ; селектор первого дескриптора (CODE_descr)
GDT:
; нулевой дескриптор (обязательно должен присутствовать в GDT!):
NULL_descr db 8 dup(0)
CODE_descr db 0FFh,0FFh,00h,00h,00h,10011010b,11001111b,00h
DATA_descr db 0FFh,0FFh,00h,00h,00h,10010010b,11001111b,00h
VIDEO_descr db 0FFh,0FFh,00h,80h,0Bh,10010010b,01000000b,00h
GDT_size equ $-GDT ; размер GDT
GDTR dw GDT_size-1 ; 16-битнvй лимит GDT
dd ? ; здесь будет 32-битнvй линейнvй адрес GDT
RM_CODE ends
...
@@start:
assume CS:RM_CODE,SS:RM_STACK
mov ax,3000h
mov ss,ax
; очистка экрана:
mov AX,3
int 10h
; для 32-х битной адресации:
in AL,92h
or AL,2
out 92h,AL
; вvчисляем линейнvй адрес метки ENTRY_POINT (точка входа в защищеннvй режим):
xor EAX,EAX ; обнуляем регистра EAX
mov AX,PM_CODE ; AX = номер сегмента PM_CODE
shl EAX,4 ; EAX = линейнvй адрес PM_CODE
add EAX,offset ENTRY_POINT ; EAX = линейнvй адрес ENTRY_POINT
mov dword ptr ENTRY_OFF,EAX ; сохраняем его в переменной
; теперь надо вvчислить линейнvй адрес GDT (для загрузки регистра GDTR):
xor EAX,EAX
mov AX,RM_CODE ; AX = номер сегмента RM_CODE
shl EAX,4 ; EAX = линейнvй адрес RM_CODE
add AX,offset GDT ; теперь EAX = линейнvй адрес GDT
; линейнvй адрес GDT кладем в заранее подготовленнуі переменнуі:
mov dword ptr GDTR+2,EAX
; собственно, загрузка регистра GDTR:
lgdt fword ptr GDTR ;ЗДЕСЬ БАГ!!!
; запрет маскируемvх прерvваний:
cli
; запрет немаскируемvх прерvваний:
in AL,70h
or AL,80h
out 70h,AL
; переключение в защищеннvй режим:
mov EAX,CR0
or AL,1
mov CR0,EAX
; загрузить новvй селектор в регистр CS
db 66h ; префикс изменения разрядности операнда
db 0EAh ; опкод командv JMP FAR
ENTRY_OFF dd ? ; 32-битное смеение
dw 00001000b ; селектор первого дескриптора (CODE_descr)
GDT:
; нулевой дескриптор (обязательно должен присутствовать в GDT!):
NULL_descr db 8 dup(0)
CODE_descr db 0FFh,0FFh,00h,00h,00h,10011010b,11001111b,00h
DATA_descr db 0FFh,0FFh,00h,00h,00h,10010010b,11001111b,00h
VIDEO_descr db 0FFh,0FFh,00h,80h,0Bh,10010010b,01000000b,00h
GDT_size equ $-GDT ; размер GDT
GDTR dw GDT_size-1 ; 16-битнvй лимит GDT
dd ? ; здесь будет 32-битнvй линейнvй адрес GDT
RM_CODE ends
...
А почему ты в реальном режиме в ss помещаешь именно 3000h? Ты уверен, что настроенный таким образом стек не будет пересекаться с образом программы в памяти? Потом, ты не показал, как инициализируется стек в защищенном режиме...
Да ошибка не в самой LGTD а где то дальше:
А вот и все остальные сегменты:
Код:
; ---------------------------------------------------------------------------------------------------------
PM_CODE segment para public 'CODE' use32
assume CS:PM_CODE, DS:PM_DATA
ENTRY_POINT:
; загрузим сегментнvе регистрv селекторами на соответствуіие дескрипторv:
mov AX,00010000b ; селектор на второй дескриптор (DATA_descr)
mov DS,AX ; в DS его
mov AX,00011000b ; селектор на третий дескриптор (VIDEO_descr)
mov ES,AX ; а этого в ES
xor ESI,ESI ; обнуляем ESI
mov SI,PM_DATA ; SI = номер сегмента PM_DATA
shl ESI,4 ; ESI = линейнvй адрес сегмента PM_DATA
add ESI,offset message ; ESI = линейнvй адрес строки message
xor EDI,EDI ; EDI = позиция на экране (относительно 0B8000h)
mov ECX,mes_len ; длина текста в ECX
; вvвод на экран:
rep movsb ; DS:ESI (наше сообение) -> ES:EDI (видеопамять)
jmp $ ; погружаемся в вечнvй цикл
PM_CODE ends
; ---------------------------------------------------------------------------------------------------------
; T++і+=T -L==-- (для Protected Mode)
; ---------------------------------------------------------------------------------------------------------
PM_DATA segment para public 'DATA' use32
assume CS:PM_DATA
; сообение, которое мv будем вvводить на экран (оформим его в виде блока повторений irpc):
message:
irpc mes, <Congratulations! We are in PM! Now you MUST Press RESET... >
db '&mes&',0Dh
endm
mes_len equ $-message ; длина в байтах
PM_DATA ends
; ---------------------------------------------------------------------------------------------------------
PM_CODE segment para public 'CODE' use32
assume CS:PM_CODE, DS:PM_DATA
ENTRY_POINT:
; загрузим сегментнvе регистрv селекторами на соответствуіие дескрипторv:
mov AX,00010000b ; селектор на второй дескриптор (DATA_descr)
mov DS,AX ; в DS его
mov AX,00011000b ; селектор на третий дескриптор (VIDEO_descr)
mov ES,AX ; а этого в ES
xor ESI,ESI ; обнуляем ESI
mov SI,PM_DATA ; SI = номер сегмента PM_DATA
shl ESI,4 ; ESI = линейнvй адрес сегмента PM_DATA
add ESI,offset message ; ESI = линейнvй адрес строки message
xor EDI,EDI ; EDI = позиция на экране (относительно 0B8000h)
mov ECX,mes_len ; длина текста в ECX
; вvвод на экран:
rep movsb ; DS:ESI (наше сообение) -> ES:EDI (видеопамять)
jmp $ ; погружаемся в вечнvй цикл
PM_CODE ends
; ---------------------------------------------------------------------------------------------------------
; T++і+=T -L==-- (для Protected Mode)
; ---------------------------------------------------------------------------------------------------------
PM_DATA segment para public 'DATA' use32
assume CS:PM_DATA
; сообение, которое мv будем вvводить на экран (оформим его в виде блока повторений irpc):
message:
irpc mes, <Congratulations! We are in PM! Now you MUST Press RESET... >
db '&mes&',0Dh
endm
mes_len equ $-message ; длина в байтах
PM_DATA ends
; ---------------------------------------------------------------------------------------------------------
Кстати сделать стек в защищёном режиме я забыл:(
Молодец! У него эмулятор ругается из-за стека, а он его просто "забыл сделать" :)
Но ведь я как видно из кода нигде после перехода в PM стек не использую!
=============================================
Ну добавил я стек для PM:
Код:
stack_Descr db 11111111b,11111111b,00000000b,00001000b,01001000b,10010001b,11001111b,00000000b
...
mov ax,00100000b
mov ss,ax
...
mov ax,00100000b
mov ss,ax
Всё равно *** Virtual machine kernel stack fault (hardware reset) ***
В этом и есть странность.
Понимаешь, чтобы стек не использовался вообще, нужно работать с запрещенными прерываниями... Более того, если у тебя произойдет какая-то ошибка, то и исключение не сможет нормально отработать, в следствие чего ты получишь hardware reset...
А каким значением ты esp инициализируешь, а то обычно стек размещают в конце сегмента, а у тебя при максимальном лимите ненулевая база почему-то...
Почему она нулевая то? (выделенно красным)
Код:
stack_Descr db 11111111b,11111111b,[COLOR="Red"]00000000b[/COLOR],[COLOR="red"]00001000b[/COLOR],[COLOR="red"]01001000b[/COLOR],10010001b,11001111b,[COLOR="red"]00000000b[/COLOR]
[COLOR="Black"]esp=FFF0h[/COLOR]
Да и ещё RESET происходит на этих строках:
Код:
mov ax,[селектор]
mov [сег.рег.],ax
mov [сег.рег.],ax
Притом независимо что за [селектор] и [сег.регистр] там указать.
Код:
stack_Descr db 11111111b,11111111b,[COLOR="Red"]00000000b[/COLOR],[COLOR="red"]00001000b[/COLOR],[COLOR="red"]01001000b[/COLOR],10010001b,11001111b,[COLOR="red"]00000000b[/COLOR]
[COLOR="Black"]esp=FFF0h[/COLOR]
[/QUOTE]
У тебя в байте флагов сегмента задан атрибут A но не задан W (разрешение записи), и еще стеку задается атрибут обратной адресации.
Вообще для стека байт флагов должен быть примерно таким (красный):
Код:
stack_Descr db 11111111b,11111111b,00000000b,00001000b,01001000b,[COLOR=red]10010110b[/COLOR],11001111b,00000000b
Может в этом проблема?
Код:
.386p
desc_struc struc
limit dw 00h ;15-0 of limit ;0-1
Base1 dw 00h ;15-0 of base ;2-3
Base2 db 00h ;23-16 of base ;4
Opt1 db 00000000b ;5
opt2 db 00000000b ;6
Base3 db 00h ;31-24 of base ;7
desc_struc ENDS
RM_CODE segment para public 'CODE' use16
assume CS:RM_CODE, DS:rM_CODE
Begin:
;Временный стек
mov ax,3000h
mov ss,ax
mov ah,00h
mov al,03h
int 10h ;очистим экран
;открыть линию А20
in AL,92h
or AL,2
out 92h,AL
;расчёт начала GDT
xor eax,eax
mov AX,RM_CODE ; AX = номер сегмента GDT
shl EAX,4 ; теперь EAX = линейнvй адрес GDT
add ax,offset GDT_BEGIN
mov dword ptr RM_CODE_Base_lo,eax
;Расчёт базы стека
xor eax,eax
mov ax,PM_STACK
shl eax,4
mov dword ptr TmpBase24_31,eax
;занесём базу стека в дескриптор:
;mov bx,OFFSET GDT_2
mov ax,word ptr TmpBase0_15
mov word ptr GDT_2.Base1,ax
mov al,byte ptr TmpBase16_23
mov byte ptr GDT_2.Base2,al
mov al,byte ptr TmpBase24_31
mov byte ptr GDT_2.Base3,al
;засунем Gdt в регистр GDTR
lgdt FWORD ptr RM_CODE_gdt_ptr
;отключим прерывания:
CLI
; запрет немаскируемvх прерываний:
in AL,70h
or AL,80h
out 70h,AL
;Посидим надорожку:) Поехали!
mov ax, 1
lmsw ax
mov esp,FFF0h
mov ax,0000000000010000b
[COLOR="Blue"]mov ss,ax ;ВОТ ЗДЕСЬ И ПРОИСХОДИТ RESET с гомким матом VMware (*** Virtual machine kernel stack fault (hardware reset) ***)[/COLOR]
sbs:
jmp sbs
GDT_BEGIN = $ ; отмечаем начало GDT
LABEL gdtadr WORD
Gdt_0 db 8 dup (00h)
GDT_2 desc_struc <Stack_end-Stack_begin,,,[COLOR="Red"]10010110b[/COLOR],01000000b,> ;Stack
;DATA
RM_CODE_gdt_ptr dw $-GDT_BEGIN ; предел таблицы GDT
RM_CODE_base_lo dw 00h ; младшее слово базового адреса GDT
RM_CODE_base_hi dw 00h ; старшее слово базового адреса GDT
;TMP:
TmpBase24_31 db 00h
TmpBase16_23 db 00h
TmpBase0_15 dw 00h
RM_CODE ends
STACK_BEGIN = $ ; отмечаем начало GDT
PM_STACK segment para stack 'STACK' use32
db 100h dup(?) ; 256 байт под стек - это даже много
PM_STACK ends
Stack_end =$
end Begin
desc_struc struc
limit dw 00h ;15-0 of limit ;0-1
Base1 dw 00h ;15-0 of base ;2-3
Base2 db 00h ;23-16 of base ;4
Opt1 db 00000000b ;5
opt2 db 00000000b ;6
Base3 db 00h ;31-24 of base ;7
desc_struc ENDS
RM_CODE segment para public 'CODE' use16
assume CS:RM_CODE, DS:rM_CODE
Begin:
;Временный стек
mov ax,3000h
mov ss,ax
mov ah,00h
mov al,03h
int 10h ;очистим экран
;открыть линию А20
in AL,92h
or AL,2
out 92h,AL
;расчёт начала GDT
xor eax,eax
mov AX,RM_CODE ; AX = номер сегмента GDT
shl EAX,4 ; теперь EAX = линейнvй адрес GDT
add ax,offset GDT_BEGIN
mov dword ptr RM_CODE_Base_lo,eax
;Расчёт базы стека
xor eax,eax
mov ax,PM_STACK
shl eax,4
mov dword ptr TmpBase24_31,eax
;занесём базу стека в дескриптор:
;mov bx,OFFSET GDT_2
mov ax,word ptr TmpBase0_15
mov word ptr GDT_2.Base1,ax
mov al,byte ptr TmpBase16_23
mov byte ptr GDT_2.Base2,al
mov al,byte ptr TmpBase24_31
mov byte ptr GDT_2.Base3,al
;засунем Gdt в регистр GDTR
lgdt FWORD ptr RM_CODE_gdt_ptr
;отключим прерывания:
CLI
; запрет немаскируемvх прерываний:
in AL,70h
or AL,80h
out 70h,AL
;Посидим надорожку:) Поехали!
mov ax, 1
lmsw ax
mov esp,FFF0h
mov ax,0000000000010000b
[COLOR="Blue"]mov ss,ax ;ВОТ ЗДЕСЬ И ПРОИСХОДИТ RESET с гомким матом VMware (*** Virtual machine kernel stack fault (hardware reset) ***)[/COLOR]
sbs:
jmp sbs
GDT_BEGIN = $ ; отмечаем начало GDT
LABEL gdtadr WORD
Gdt_0 db 8 dup (00h)
GDT_2 desc_struc <Stack_end-Stack_begin,,,[COLOR="Red"]10010110b[/COLOR],01000000b,> ;Stack
;DATA
RM_CODE_gdt_ptr dw $-GDT_BEGIN ; предел таблицы GDT
RM_CODE_base_lo dw 00h ; младшее слово базового адреса GDT
RM_CODE_base_hi dw 00h ; старшее слово базового адреса GDT
;TMP:
TmpBase24_31 db 00h
TmpBase16_23 db 00h
TmpBase0_15 dw 00h
RM_CODE ends
STACK_BEGIN = $ ; отмечаем начало GDT
PM_STACK segment para stack 'STACK' use32
db 100h dup(?) ; 256 байт под стек - это даже много
PM_STACK ends
Stack_end =$
end Begin
Но всё равно [COLOR="Red"]*** Virtual machine kernel stack fault (hardware reset) ***[/COLOR] на mov ss,ax
Блин, не могу понять (не посчитайте за тупого:) ) в чём же ошибка?
Не обязательно для стека использовать растущий вниз сегмент, но верно то, что этот сегмент должен допускать запись! piroman17, в твоем случае нет необходимости в установке бита "растущий вниз сегмент", потому что кроме лишних сложностей это ничего не дает. Попробуй снять этот бит... И еще одно: после переключения в PM первым делом рекомендуется устанавливать cs, т.е. делать дальний переход.
Цитата:
после переключения в PM первым делом рекомендуется устанавливать cs, т.е. делать дальний переход
Я бы даже сказал обязательно, это нужно процу чтобы правильно установить базу, размер и атрибуты сегмента кода.
А к чему относится порт 92h?
а то я все по старинке (A20) :(
Код:
mov al, 0D1h
out 64h, al
mov al, 0DFh
out 60h, al
out 64h, al
mov al, 0DFh
out 60h, al
поделиться...
HexEdit, твой способ такой же неуниверсальный, как и использование исключительно порта 92h! Установку линии A20 следует выполнять, последовательно осуществляя три(!!!) разных метода установки и проверяя факт установки после каждой попытки. Подробно объяснять не буду, но интересной статьёй на эту тему могу
Не обязательно для стека использовать растущий вниз сегмент, но верно то, что этот сегмент должен допускать запись! piroman17, в твоем случае нет необходимости в установке бита "растущий вниз сегмент", потому что кроме лишних сложностей это ничего не дает. Попробуй снять этот бит... И еще одно: после переключения в PM первым делом рекомендуется устанавливать cs, т.е. делать дальний переход.[/QUOTE]
Конечно со стеком ты прав... но вот интересная мысля (самому проверять неохота) в дескрипторе 20 битный лимит, т.е. в сегменте данных с расширением вниз будет диапазон допустимых адресов от limit +1 до FFFFFFFFh, но как проц трактует этот лимит при грануляции сегмента в байтах??? если напрямую, то что, минимальный размер стека получается FFFFFFFFh - maxLIMIT= FFFFFFh - FFFFFh = FFF00000h = 4 293 918 720 байт??? не хило... или же он же он считает у таких сегментов при грануляции в байтах лимит как число FFF<LIMIT>h? и тогда минимальный размер стека вообще получается ZERO, а максимальный - 1 048 575 байт?
Код:
.386p
desc_struc struc
limit dw 00h ;15-0 of limit ;0-1
Base1 dw 00h ;15-0 of base ;2-3
Base2 db 00h ;23-16 of base ;4
Opt1 db 00000000b ;5
opt2 db 00000000b ;6
Base3 db 00h ;31-24 of base ;7
desc_struc ENDS
RM_CODE segment para public 'CODE' use16
assume CS:RM_CODE, DS:rM_CODE
Begin:
;Временный стек
mov ax,3000h
mov ss,ax
mov ah,00h
mov al,03h
int 10h ;очистим экран
;открыть линию А20
in AL,92h
or AL,2
out 92h,AL
;расчёт начала GDT
xor eax,eax
mov AX,RM_CODE ; AX = номер сегмента GDT
shl EAX,4 ; теперь EAX = линейнvй адрес GDT
add ax,offset GDT_BEGIN
mov dword ptr RM_CODE_Base_lo,eax
;Расчёт базы стека
xor eax,eax
mov ax,PM_STACK
shl eax,4
mov dword ptr TmpBase24_31,eax
;занесём базу стека в дескриптор:
;mov bx,OFFSET GDT_2
mov ax,word ptr TmpBase0_15
mov word ptr GDT_2.Base1,ax
mov al,byte ptr TmpBase16_23
mov byte ptr GDT_2.Base2,al
mov al,byte ptr TmpBase24_31
mov byte ptr GDT_2.Base3,al
;засунем Gdt в регистр GDTR
lgdt FWORD ptr RM_CODE_gdt_ptr
;отключим прерывания:
CLI
; запрет немаскируемvх прерываний:
in AL,70h
or AL,80h
out 70h,AL
;Посидим надорожку:) Поехали!
mov ax, 1
lmsw ax
mov esp,FFF0h
mov ax,0000000000010000b
[COLOR="Blue"]mov ss,ax ;ВОТ ЗДЕСЬ И ПРОИСХОДИТ RESET с гомким матом VMware (*** Virtual machine kernel stack fault (hardware reset) ***)[/COLOR]
sbs:
jmp sbs
GDT_BEGIN = $ ; отмечаем начало GDT
LABEL gdtadr WORD
Gdt_0 db 8 dup (00h)
GDT_2 desc_struc <Stack_end-Stack_begin,,,[COLOR="Red"]10010110b[/COLOR],01000000b,> ;Stack
;DATA
RM_CODE_gdt_ptr dw $-GDT_BEGIN ; предел таблицы GDT
RM_CODE_base_lo dw 00h ; младшее слово базового адреса GDT
RM_CODE_base_hi dw 00h ; старшее слово базового адреса GDT
;TMP:
TmpBase24_31 db 00h
TmpBase16_23 db 00h
TmpBase0_15 dw 00h
RM_CODE ends
STACK_BEGIN = $ ; отмечаем начало GDT
PM_STACK segment para stack 'STACK' use32
db 100h dup(?) ; 256 байт под стек - это даже много
PM_STACK ends
Stack_end =$
end Begin
desc_struc struc
limit dw 00h ;15-0 of limit ;0-1
Base1 dw 00h ;15-0 of base ;2-3
Base2 db 00h ;23-16 of base ;4
Opt1 db 00000000b ;5
opt2 db 00000000b ;6
Base3 db 00h ;31-24 of base ;7
desc_struc ENDS
RM_CODE segment para public 'CODE' use16
assume CS:RM_CODE, DS:rM_CODE
Begin:
;Временный стек
mov ax,3000h
mov ss,ax
mov ah,00h
mov al,03h
int 10h ;очистим экран
;открыть линию А20
in AL,92h
or AL,2
out 92h,AL
;расчёт начала GDT
xor eax,eax
mov AX,RM_CODE ; AX = номер сегмента GDT
shl EAX,4 ; теперь EAX = линейнvй адрес GDT
add ax,offset GDT_BEGIN
mov dword ptr RM_CODE_Base_lo,eax
;Расчёт базы стека
xor eax,eax
mov ax,PM_STACK
shl eax,4
mov dword ptr TmpBase24_31,eax
;занесём базу стека в дескриптор:
;mov bx,OFFSET GDT_2
mov ax,word ptr TmpBase0_15
mov word ptr GDT_2.Base1,ax
mov al,byte ptr TmpBase16_23
mov byte ptr GDT_2.Base2,al
mov al,byte ptr TmpBase24_31
mov byte ptr GDT_2.Base3,al
;засунем Gdt в регистр GDTR
lgdt FWORD ptr RM_CODE_gdt_ptr
;отключим прерывания:
CLI
; запрет немаскируемvх прерываний:
in AL,70h
or AL,80h
out 70h,AL
;Посидим надорожку:) Поехали!
mov ax, 1
lmsw ax
mov esp,FFF0h
mov ax,0000000000010000b
[COLOR="Blue"]mov ss,ax ;ВОТ ЗДЕСЬ И ПРОИСХОДИТ RESET с гомким матом VMware (*** Virtual machine kernel stack fault (hardware reset) ***)[/COLOR]
sbs:
jmp sbs
GDT_BEGIN = $ ; отмечаем начало GDT
LABEL gdtadr WORD
Gdt_0 db 8 dup (00h)
GDT_2 desc_struc <Stack_end-Stack_begin,,,[COLOR="Red"]10010110b[/COLOR],01000000b,> ;Stack
;DATA
RM_CODE_gdt_ptr dw $-GDT_BEGIN ; предел таблицы GDT
RM_CODE_base_lo dw 00h ; младшее слово базового адреса GDT
RM_CODE_base_hi dw 00h ; старшее слово базового адреса GDT
;TMP:
TmpBase24_31 db 00h
TmpBase16_23 db 00h
TmpBase0_15 dw 00h
RM_CODE ends
STACK_BEGIN = $ ; отмечаем начало GDT
PM_STACK segment para stack 'STACK' use32
db 100h dup(?) ; 256 байт под стек - это даже много
PM_STACK ends
Stack_end =$
end Begin
Но всё равно [COLOR="Red"]*** Virtual machine kernel stack fault (hardware reset) ***[/COLOR] на mov ss,ax
Блин, не могу понять (не посчитайте за тупого:) ) в чём же ошибка?[/QUOTE]
Если хотишь использовать в качестве стека сегмент с расширением вниз, то поставь лучше базу, как первый байт следующий за стеком... А то ты стек суешь в запрещенные адреса...
Вообще для стека байт флагов должен быть примерно таким (красный):
Код:
stack_Descr db 11111111b,11111111b,00000000b,00001000b,01001000b,[COLOR=red]10010110b[/COLOR],11001111b,00000000b
Может в этом проблема?[/QUOTE]
Сколько проблем со стеком... вообще - то с расширением вниз делают токо тогда стек, когда динамически, по мере надобности, хотят его увеличивать... Да и вообще зачем PM? REAL MODE - вот рулез!
;
;
; СИНТАКСИС ДЛЯ FASM %-)
;
;
format MZ
entry main:start
segment main use16
start:
push word gdt_seg ; загрузка в DS сегмента с будущей GDT
pop ds
mov ah,00h
mov al,03h
int 10h ;очистим экран
xor eax,eax
mov ax,gdt_seg
sal eax,4
or dword [base_gdt],eax ; установим базу для дескриптора gdt...
mov dword [base_gdt_reg],eax
xor eax,eax
mov ax,pm_code
sal eax,4
or dword [base_code],eax ; для сегмента кода
xor eax,eax
mov ax,stek
sal eax,4
or dword [base_stek],eax ; для стека
xor eax,eax ; установим базу для сегмента данных
mov ax,pm_data
sal eax,4
or dword [base_data],eax
lgdt pword [gdt_reg] ; загрузим gdtr
cli
mov eax,cr0 ; идем в протект
or eax,1
mov cr0,eax
call far pword 010000b:pm_entry ; дальний переход на входную метку
; ...
segment pm_code use32
code_beg = $
pm_entry:
mov ax,011000b ; установим стек
mov ss,ax
mov esp,stek_size-5
push word 100000b ; установим используемые селекторы (ES - сегмент текст. буфера
pop es ; DS - сегмент данных
push word 101000b
pop ds
mov esi,messeage ; зададим знач. для функции вывода (ds:esi - смещ выводимой строки
mov ecx,12 ; ecx - сколько писать, edi - номер символа выводимой строки)
xor edi,edi
call near dword text
hlt ; остановим работу процессора
text: ; :-)
push ecx
movzx edi,di
and di,0fffeh
movzx ecx,cx
mov ah,017h
.zikl:
mov al,[esi]
es mov word [edi],ax
add edi,2
movzx edi,di
inc esi
loop .zikl
pop ecx
retnd
code_size = code_beg-$
segment pm_data use16
data_beg = $
messeage db 'Hello world!' ; типа здравие желаю...
rd 10
data_size = data_beg-$
segment stek use16
stek_beg = $
rd 100
stek_size = stek_beg-$
segment gdt_seg use16
gdt_beg = $
void_desc dd 0 ; пустой дескриптор
dd 0
gdt_desc dw gdt_size-1 ; дескриптор описывающий GDT, вдруг захош дескр. переписать
base_gdt dw 0
db 0
db 10010010b
dw 0
code_desc dw code_size-1 ; сегмент кода
base_code dw 0
db 0
db 10011010b
dw 01000000b ; будет 32 битный
stek_desc dw stek_size-1 ; стек с расширением вверх
base_stek dw 0
db 0
db 10010010b
dw 0
graf_desc dw 0ffffh ; текстовый буфер
dw 08000h
db 0bh
db 10010010b
dw 0
data_desc dw data_size-1 ; сегмент данных
base_data dw 0
db 0
db 10010010b
dw 0
real_flat_desc dw 0ffffh ; не нужная хрень, но приготиться для возврата в Реал...
dw 0
db 0
db 10010010b
dw 0
gdt_size = gdt_beg - $
gdt_reg dw gdt_size-1 ; псевдодескриптор GDT
base_gdt_reg dd 0
[QUOTE=infernodiablo]Конечно со стеком ты прав... но вот интересная мысля (самому проверять неохота) в дескрипторе 20 битный лимит, т.е. в сегменте данных с расширением вниз будет диапазон допустимых адресов от limit +1 до FFFFFFFFh, но как проц трактует этот лимит при грануляции сегмента в байтах??? если напрямую, то что, минимальный размер стека получается FFFFFFFFh - maxLIMIT= FFFFFFh - FFFFFh = FFF00000h = 4 293 918 720 байт??? не хило... или же он же он считает у таких сегментов при грануляции в байтах лимит как число FFF<LIMIT>h? и тогда минимальный размер стека вообще получается ZERO, а максимальный - 1 048 575 байт?[/QUOTE]Принцип такой же, просто когда лимит указывается в байтах, размер сегмента не может превышать 64 Кб (не 4 Гб), т.е. вычислять нужно так 0FFFFh - 0FFFFh = 0 (нулевой размер!!!) и 0FFFFh - 0 = 0FFFFh (64 Кб минус 1 байт). Иными словами, расширяемый вниз сегмент не может быть размером 64 Кб (4 Гб), но зато может иметь нулевой размер!
... Сказки... если бит грануляции снят (т.е. лимит в байтах, а не в страницах), то размер сегмента не может превышать 1 МЕГАБАЙТ (проверено на практике), т.к. поле границы - 20 битное, а не 16 битное... , а 64 кб это на допотопных процах типа 286
P.S. это я про дескрипторы начиная с 486 где 20 битный лимит, 32 битная база...
P.S. В моей оси значения бита разрядности и бита гранулярности в сегментных дескрипторах всегда совпадают! Дескрипторы с G=B=0 используются лишь при возврате в реальный режим во время парковки системы. В экспериментальных версиях, в которых парковка осуществляется без возврата в реальный режим, используются только сегментные дескрипторы с G=B=1...
;
;
; СИНТАКСИС ДЛЯ FASM %-)
;
;
format MZ
entry main:start
segment main use16
start:
push word gdt_seg ; загрузка в DS сегмента с будущей GDT
pop ds
mov ah,00h
mov al,03h
int 10h ;очистим экран
xor eax,eax
mov ax,gdt_seg
sal eax,4
or dword [base_gdt],eax ; установим базу для дескриптора gdt...
mov dword [base_gdt_reg],eax
xor eax,eax
mov ax,pm_code
sal eax,4
or dword [base_code],eax ; для сегмента кода
xor eax,eax
mov ax,stek
sal eax,4
add eax,stek_size
mov word [base_stek],ax ; установим базу для стека как байт следующий за стеком
shr eax,16
mov byte [stek_desc+4],al
mov byte [stek_desc+7],ah
mov eax,0fffffh ; интерпретируем 20 битную границу
sub eax,stek_size
mov word [stek_desc],ax
shr eax,16
or byte [stek_desc+6],al
xor eax,eax ; установим базу для сегмента данных
mov ax,pm_data
sal eax,4
or dword [base_data],eax
lgdt pword [gdt_reg] ; загрузим gdtr
cli
mov eax,cr0 ; идем в протект
or eax,1
mov cr0,eax
call far pword 010000b:pm_entry ; дальний переход на входную метку
; ...
segment pm_code use32
code_beg = $
pm_entry:
mov ax,011000b ; установим стек
mov ss,ax
mov esp,0fffffff0h
mov ebp,0ffffffffh
sub ebp,stek_size
;ss mov byte [ebp],2 ; если пропуск снять ; , то программа не заработает
push word 100000b ; установим используемые селекторы (ES - сегмент текст. буфера
pop es ; DS - сегмент данных
push word 101000b
pop ds
ss cmp byte [ebp+1],1ah ; если стек не в том сегмете, тогда буква H не сотрется
jne .next
and byte [messeage],0
.next:
mov esi,messeage ; зададим знач. для функции вывода (ds:esi - смещ выводимой строки
mov ecx,12 ; ecx - сколько писать, edi - номер символа выводимой строки)
xor edi,edi
call near dword text
hlt ; остановим работу процессора
text: ; :-)
push eax
push ecx
movzx edi,di
and di,0fffeh
movzx ecx,cx
mov ah,017h
.zikl:
mov al,[esi]
es mov word [edi],ax
add edi,2
movzx edi,di
inc esi
loop .zikl
pop ecx
pop eax
retnd
code_size = code_beg-$
segment pm_data use16
data_beg = $
messeage db 'Hello world!' ; типа здравие желаю...
rd 10
data_size = data_beg-$
segment stek use16
stek_beg = $
db 1ah
rd 1024
stek_size = stek_beg-$
segment gdt_seg use16
gdt_beg = $
void_desc dd 0 ; пустой дескриптор
dd 0
gdt_desc dw gdt_size-1 ; дескриптор описывающий GDT, вдруг захош дескр. переписать
base_gdt dw 0
db 0
db 10010010b
dw 0
code_desc dw code_size-1 ; сегмент кода
base_code dw 0
db 0
db 10011010b
dw 01000000b ; будет 32 битный
stek_desc dw 0 ; стек с расширением вниз
base_stek dw 0
db 0
db 10010110b
dw 0
graf_desc dw 0ffffh ; текстовый буфер
dw 08000h
db 0bh
db 10010010b
dw 0
data_desc dw data_size-1 ; сегмент данных
base_data dw 0
db 0
db 10010010b
dw 0
real_flat_desc dw 0ffffh ; не нужная хрень, но приготиться для возврата в Реал...
dw 0
db 0
db 10010010b
dw 0fh
gdt_size = gdt_beg - $
gdt_reg dw gdt_size-1 ; псевдодескриптор GDT
base_gdt_reg dd 0
Следую предположению что процессор считает допустимыми адресами в сегменте с расширением вниз от FFF<limit> до FFFFFFFFh я установил базу сегмента как первый байт следующий за стеком, соответствующим образом интерпретировал границу. После перехода в защищенный режим регистр ESP устанавливается со значением 0FFFFFFF0h, и устанавливается SS на сегмент стека с расширением вниз. Судя по тому что программа нормально работала (без перезагрузки, происходящей при исключении) делаю вывод, что предположение верно. Чтобы проверить правильно, и втом ли месте создан сегмент стека, я в нем первый байт установил как маркер со значением 1ah, в работе программы если маркер прочитаный по адресу FFF<limit>+1 является установленным маркером, то стирается буква "H" в выводимой строке. Для проверки границы стека установил команду, которая пытается писать по адресу FFF<limit>, при установленной этой команде программа вызывала исключение и перезагружала комп.
ВЫВОД: При работе в защищенном режиме, процессор считает разрешенными адресами (при которых не возникает исключение общей защиты) от FFF<limit>+1 до FFFFFFFFh и следовательно минимальный размер стека с расширением вниз = 0, максимальный = 1 Мб
P.S. Как вы делаете текст программы в окошке с прокруткой?
P.S. В моей оси значения бита разрядности и бита гранулярности в сегментных дескрипторах всегда совпадают! Дескрипторы с G=B=0 используются лишь при возврате в реальный режим во время парковки системы. В экспериментальных версиях, в которых парковка осуществляется без возврата в реальный режим, используются только сегментные дескрипторы с G=B=1...[/QUOTE]
Принципы совместимости??? может ты и прав, но я в своей жизни не разу не видел проц. intel 80286 и по моему писать программы совместимые с этими неиспользуемым более 10 лет процессорами нецелесообразно...
P.S. Используй парный тег code в кв. скобках :)
Ты ОС пишешь??? на чем и для какой цели?
P.S. Используй парный тег code в кв. скобках :)[/QUOTE]
Дык это понятно, что сегмент с расширением вниз имеет максимальный размер на 1 байт меньше (или страницу), чем его сородич с расширением вверх
Это хобби, на ассемблере (fasm)...
Блин... а я уж начал думать что на fasm только я (дурак) один пишу... мне не нравиться в нем что он когда делает программу не выдает листинг в файл... а бывает где -нибудь допустишь ошибку, типа метку забудешь поставить а в команде перехода ее напишешь, то он вообще ошибку не показывает и компилировать отказывается...
У меня к fasm'у вообще нет никаких претензий. Он мне очень нравится!!! Я даже приложения под винды на нем частенько пишу!
У тебя какая версия?
version 1.20 если есть новее, то давай мне ссылочку на сайт, где можно его качнуть...
P.S. Мне он тоже нравится, в нем нет лишнего как в tasm и позволяет написать нечто вроде call far dword 123:5678, на что некоторые ассемблеры ругаются... но только вот с макросами я в нем так и не разобрался... пишу без них :-)
http://flatassembler.net/download.php. Актуальная версия сейчас - 1.67.7.
На http://flatassembler.net/ много полезного.
ЗЫ. FASM - RULEZZZ!!!
FASM качать с
На http://flatassembler.net/ много полезного.
ЗЫ. FASM - RULEZZZ!!!
Код:
[COLOR="Red"]shl eax,4[/COLOR]
Написал в исходном коде Shl eax,3 и думал почему всё глючит!
Кстати тут на форуме (mes#16) я написал Shl eax,4:D
во все сегменты всё пишется КРОМЕ [COLOR="red"]CS[/COLOR]
Может я не верно указал параметры сегмента:confused:
Код:
... 10011000b, 00000000b ...
Параметры правильно. А как ты CS илициализируешь?
1.20 - это очень древняя версия!!! Я три года назад уже пользовался версией 1.44, а сейчас использую 1.64!
Код:
GDT_1 desc_struc <PM_CODE_END-PM_CODE_Begin,,,10011110b,00000000b,>
Это я вычисляю начало PM_CODE:
Код:
;Расчёт базы кода
xor eax,eax
mov ax,cs
shl eax,4
add ax,offset PM_CODE
mov dword ptr TmpBase24_31,eax
;занесём базу кода в дескриптор:
mov al,byte ptr TmpBase0_15
mov byte ptr GDT_1.Base1,al
mov ax,word ptr TmpBase16_23
mov word ptr GDT_1.Base2,ax
mov al,byte ptr TmpBase24_31
mov byte ptr GDT_1.Base3,al
xor eax,eax
mov ax,cs
shl eax,4
add ax,offset PM_CODE
mov dword ptr TmpBase24_31,eax
;занесём базу кода в дескриптор:
mov al,byte ptr TmpBase0_15
mov byte ptr GDT_1.Base1,al
mov ax,word ptr TmpBase16_23
mov word ptr GDT_1.Base2,ax
mov al,byte ptr TmpBase24_31
mov byte ptr GDT_1.Base3,al
А вот сам инит:
Код:
db 66h ;префикс изменения разрядности операнда
db 0EAh ; опкод команды JMP FAR
dd 00h ; 32-битное смещение
dw 00001000b ; селектор первого дескриптора (CODE_descr)
db 0EAh ; опкод команды JMP FAR
dd 00h ; 32-битное смещение
dw 00001000b ; селектор первого дескриптора (CODE_descr)
Мне кажется проц почему то не хочет менять CS:confused: .
Кстати ещё... Написал обработчик прерываний таже проблема: при первом же прерывании RESET:mad:
Сразу говорю обработчик простой: там только "Конец прерывания" и IRET, врятли там есть ошибка.