001 format binary
002 org 0
003 include 'kboot.inc'
004 include 'pmode.inc'
005 include 'routines.inc'
006
007 code_selector = 8
008 stack_selector = 16
009 data_selector = 24
010 screen_selector = 32
011 rcode_selector = 40
012 rdata_selector = 48
013
014 use16
015
016 start:
017 ; load segment regs, set stack
018 cli
019 mov ax,cs
020 mov ds,ax
021 mov es,ax
022 mov ss,ax
023 mov sp,stacksize
024 sti
025
026 ; show hello msg
027 mov si, szLoaderMsg
028 call kputzs_bios
029
030 ; msg about pmode entering
031 mov si, szMsgPMEnter
032 call kputzs_bios
033
034 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
035 ; save real mode descriptors
036 mov [rmode_ss],ss
037 mov [rmode_ds],ds
038 mov [rmode_es],es
039 mov [rmode_fs],fs
040 mov [rmode_gs],gs
041
042 ; set real mode return address
043 mov [rmode_seg],cs
044 lea ax,[rmode_entry]
045 mov [rmode_off],ax
046
047 mov bx,gdt+8 ; skip zero-descriptor
048
049 xor eax,eax
050 mov edx,eax
051
052 push cs
053 pop ax ; ax = cs = segment address of current code segment
054
055 shl eax,4 ; eax = physical address of beginning of code segment
056
057
058 ; set limit-hi and GDXU bits
059 ; limit-hi = 0Fh (maximum), G=1 (4 kbyte pages), D=1 (32 bit),
060 ; X=0 (reserved, must be 0), U=0 (for system purposes)
061 mov dx,11001111b
062 shl edx,16 ; move them to edx-hi part
063 mov dx,0FFFFh ; set limit-low (here - maximum)
064 ; finaly we have 4Gbyte limit for code descriptor
065
066 ; code segment access rights (P = 1,
067 ; DPL = 00b, S = 1, type = 100b, A = 0)
068 mov cl,10011000b
069
070 call gdt_set_desc ; build code descriptor
071
072 lea dx,[stack_seg_start] ; edx = dx = stack beginning
073
074 add eax,edx ; eax - beginning of code segment
075 ; set limit-hi and GDXU bits
076 ; limit-hi = 00h (zero), G=1 (4 kbyte pages), D=1 (32 bit),
077 ; X=0 (reserved, must be 0), U=0 (for system purposes)
078 mov dx,11001111b
079 shl edx,16 ; move them to edx-hi part
080 mov dx,1024 ; set limit-low (stack size)
081
082 ; stack segment access rights
083 ; (P = 1, DPL = 00b, S = 1,
084 ; type = 011b, A = 0).
085 mov cl,10010110b
086
087 call gdt_set_desc ; build stack descriptor
088
089 xor eax,eax ; eax = 0
090 mov ax,ds
091 shl eax,4 ; ecx = physical address of beginning of data segment
092 mov dx,11001111b ; set limit-hi and GDXU bits
093 shl edx,16
094 mov dx,0FFFFh ; limit - maximum
095 ; 4GB data segment is ready
096
097 ; data segment access rights (P = 1,
098 ; DPL = 00b, S = 1, type = 001, A = 0).
099 mov cl,10010010b
100
101 call gdt_set_desc ; build data descriptor
102
103 mov eax,0B8000h ; physical address of videomem segment beginning
104
105 mov edx,4000 ; videomem segment size (80*25*2 = 4000).
106 mov cl,10010010b ; access rights (like data segment)
107 call gdt_set_desc ; build video memory segment
108
109 ; now set additional real mode selectors
110 xor eax,eax
111 mov edx,eax
112
113 push cs
114 pop ax
115
116 shl eax,4 ; eax - physical address of code segment
117
118 mov edx,0FFFFh
119 mov cl,10011010b
120 call gdt_set_desc ; rmode code
121
122 mov cl,10010010b
123 call gdt_set_desc ; rmode data
124
125
126 ; set gdtr:
127
128 xor eax,eax ; eax = 0
129 mov edx,eax ; edx = 0
130
131 mov ax,ds
132 shl eax,4 ; eax = physical address of beginning of data segment
133 lea dx,[gdt]
134 add eax,edx ; eax = physical address of gdt
135 mov [gdt_adr],eax ; save it in gdt address field
136
137 mov dx,55 ; gdt limit = 8 * (1 + 6) - 1
138 mov [gdt_lim],dx ; save it in gdtr limit field
139
140 cli ; disable interrupts
141
142 lgdt [gdtr] ; load gdtr
143
144 mov [rmode_sp],sp ; save stack pointer at the end
145
146 ; go to pmode
147
148 mov eax,cr0
149 or al,1
150 mov cr0,eax
151
152 ; load code selector into cs register
153 ; using far jump to pmode code
154
155 jmp far code_selector:pmode_entry
156
157 ;--------------------- now we're in 32 bit PM-------------------------------
158 use32
159 pmode_entry:
160 ; cs - code segment selector
161 ; load segment registers
162 mov ax,screen_selector
163 mov es,ax
164
165 mov ax,data_selector
166 mov ds,ax
167
168 mov ax,stack_selector
169 mov ss,ax
170 mov sp,0
171
172 ; show what we are now in pmode
173 mov ebx,szMsgPM ; ds:ebx - msg pointer
174 mov edi,480 ; 3 string in video memory
175 call kputzs ; print msg from pmode
176
177 ; entering rmode
178 mov ebx,szMsgRMEnter ; ds:ebx - msg pointer
179 mov edi,640 ; 4 string in video memory
180 call kputzs ; print msg from pmode
181
182 jmp far rcode_selector:rmode_preentry
183
184 rmode_preentry:
185 mov ax,rdata_selector
186 mov ss,ax
187 mov ds,ax
188 mov es,ax
189 mov fs,ax
190 mov gs,ax
191
192 mov eax,cr0
193 and al,0FEh
194 mov cr0,eax
195
196 ; far jump to real mode
197 ; jmp far rmode_seg:rmode_off
198 db 0eah
199 rmode_off dw 0
200 rmode_seg dw 0
201
202 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
203 ; ---------------------------- routines ----------------------------------
204 init_kputzs ; printing routine (uses video memory)
205 use16
206 init_gdt_set_desc ; gdt setting routine
207 init_kputzs_bios ; printing routine (uses int10)
208 init_set_curpos_bios ; setting cursor routine
209
210 ; real mode now
211 rmode_entry:
212 ; restore ss,ds,es,gs,fs
213 mov ss,[rmode_ss]
214 mov ds,[rmode_ds]
215 mov es,[rmode_es]
216 mov gs,[rmode_gs]
217 ; restore stack pointer
218 mov sp,[rmode_sp]
219
220 ; allow interrupts
221 sti
222 jmp $
223
224 ; set cursor to the 5th line
225 mov dx,0500h
226 call set_curpos_bios
227
228 mov si,szMsgRM
229 call kputzs_bios
230
231 jmp $
232
233 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
234
235 ; gdt register image:
236
237 gdtr:
238 gdt_lim dw 0
239 gdt_adr dd 0
240 ;--------------------------------------------------------------------------
241 gdt:
242 dd 0,0 ; 0 descriptor
243 dd 0,0 ; 1 descriptor (code)
244 dd 0,0 ; 2 descriptor (stack)
245 dd 0,0 ; 3 descriptor (data)
246 dd 0,0 ; 4 descriptor (videomem)
247 dd 0,0 ; 5 descriptor (realm code)
248 dd 0,0 ; 6 descriptor (realm data)
249 real:
250 rmode_sp dw 0
251 rmode_ss dw 0
252 rmode_ds dw 0
253 rmode_es dw 0
254 rmode_fs dw 0
255 rmode_gs dw 0
256
257 szLoaderMsg db 'HELLO FROM KLOADER!!',13,10,0
258 szMsgPMEnter db 'ENTERING PMODE...',13,10,0
259 szMsgRM db 'IN 16 BIT UNREAL MODE NOW!',13,10,0
260
261
262 ;--------------------------------------------------------------------------
263
264 szMsgPM db 'IN 32 BIT PMODE NOW!',0
265 szMsgRMEnter db 'ENTERING RMODE...',0
266
267
268 times 1024 db 0 ; reserved for stack
269 stack_seg_start: ; stack beginning
проблемы с прерываниями при переходе из защищенного в реальный
написал я вторичный загрузчик (в будущем), который грузится из фат-раздела по адресу 01000h и выполняет следующие операции:
отключает прерывания, сохраняет текущие значения ss,ds,es и др. в память для возврата в реальный режим, создает дескрипторы кода (4Gb), данных (по такому же адресу что и code), стэка (фиксирован), видеопамяти (по адресу 0B8000h, размер 4000) для защищенного режима и 2 дескриптора кода и данных (16 бит, лимит 0FFFFh) для реального, настаивает gdt и загружает ее.
потом в защищенном режиме выводит пару строк и переходит назад в реальный.
но проблема вот в чем.. при включении прерываний уже в реальном режиме, система попросту перезагружается (если запускать на реальной машине), а если на vmware (4.05) или Bochs (2.26) то все нормально, т.е. sti включает прерывания и далее выводится строка посредством int10h
см. строку 221
я если чесно понятия не имею почему так происходит и поэтому прошу помочь.
вот код загрузчика:
Код:
вот код процедуры создания дескрипторов gdt_set_desc:
Код:
001 ; gdt descriptor setting subroutine
002
003 ; creates descriptor
004 ; DS:BX = descriptor in gdt
005 ; EAX = segment address
006 ; EDX = segment limit
007 ; CL = access rights byte
008 macro init_gdt_set_desc {
009 gdt_set_desc:
010
011 push eax ecx edx ; we use eax, ecx, edx
012
013
014 push cx ; temporary save access rights
015
016 mov cx,ax ; copy lower part of address to cx,
017 shl ecx,16 ; and shift it to higher part
018
019 ; copy lower part of limit to cx
020 ; now ecx contains lower part of
021 ; the descriptor
022 mov cx,dx
023
024 mov [bx],ecx ; write lower part of descriptor to gdt
025
026 shr eax,16 ; now shift higher part of address to lower (ax)
027
028 mov ch,ah ; address bits 24 - 31
029 shr edx,16 ; working with higher part of limit (limit hi+GDXU)
030 mov cl,dl ; limit bits 16-19 + GDXU
031 shl ecx,16 ; shift it to higher part of ecx
032 mov cl,al ; and address bits 16 - 23 - lower byte
033
034 pop ax ; restore access rights to ax
035 ; and copy them into the second byte (of 4 available)
036 ; of ecx
037 mov ch,al
038
039 ; write the second part of
040 ; descriptor into gdt
041 mov [bx+4],ecx
042
043 add bx,8 ; move gdt poiner to next descriptor
044 pop edx ecx eax
045 ret
046 }
047
002
003 ; creates descriptor
004 ; DS:BX = descriptor in gdt
005 ; EAX = segment address
006 ; EDX = segment limit
007 ; CL = access rights byte
008 macro init_gdt_set_desc {
009 gdt_set_desc:
010
011 push eax ecx edx ; we use eax, ecx, edx
012
013
014 push cx ; temporary save access rights
015
016 mov cx,ax ; copy lower part of address to cx,
017 shl ecx,16 ; and shift it to higher part
018
019 ; copy lower part of limit to cx
020 ; now ecx contains lower part of
021 ; the descriptor
022 mov cx,dx
023
024 mov [bx],ecx ; write lower part of descriptor to gdt
025
026 shr eax,16 ; now shift higher part of address to lower (ax)
027
028 mov ch,ah ; address bits 24 - 31
029 shr edx,16 ; working with higher part of limit (limit hi+GDXU)
030 mov cl,dl ; limit bits 16-19 + GDXU
031 shl ecx,16 ; shift it to higher part of ecx
032 mov cl,al ; and address bits 16 - 23 - lower byte
033
034 pop ax ; restore access rights to ax
035 ; and copy them into the second byte (of 4 available)
036 ; of ecx
037 mov ch,al
038
039 ; write the second part of
040 ; descriptor into gdt
041 mov [bx+4],ecx
042
043 add bx,8 ; move gdt poiner to next descriptor
044 pop edx ecx eax
045 ret
046 }
047
буду очень благодарен за помощь
заранее спасибо
Попробуй по-человечьи настроить IDT. Желательно как при переходе в защищенный режим, так и обратно. Хотя это потребует немало дополнительной работы - перепрограммирования микросхем управления аппаратными прерываниями. Но оно тебе все равно будет нужно, я думаю. Ведь не собираешься же ты и дальше грузить систему с запрещенными прерываниями.
спасибо за совет, но нельзя ли по-подробнее? как и что надо настроить? а главное почему не работает на реальной машине а на виртуалках все ок?
выкладываю полный исходник+образ дискеты на всякий случай
NeTxXx, а что по твоему делает инструкция "jmp $" после разрешения прерываний в реальном режиме :)
может пример есть перехода в pmode а потом обратно? посоветуйте пожалуйста
может пример есть перехода в pmode а потом обратно? посоветуйте пожалуйста[/QUOTE]дык для того, что делает твоя программа, код у тебя слишком сложный... Это же ассемблер! Пиши предельно прозрачно, иначе потом разгребать замучаешься... А вообще есть множество примеров перехода в PM и обратно! Если хочешь, можем разобрать твой код по шагам...
и еще, я смотрел примеры перехода в pmode и назад, сделано все как у меня.. никаких настроек контроллера прерываний не производится, однако сброса после sti не возникает? странно, почему? и больше всего меня мучает вопрос почему в виртуальной среде эмуляторов такое не происходит? может обратиться к их разработчикам? мол почему этот код не работает на реальной машине, а на виртуальной все ок? )) причем сразу в обоих эмуляторах!
Цитата:
...а вот от разбора я бы не отказался.. только как это будет выглядеть? ...больше всего меня мучает вопрос почему в виртуальной среде эмуляторов такое не происходит?
Элементарно! Напишем заново :) С эмуляторами такое постоянно случается, поэтому я их редко использую... Но возможно, что у тебя все-таки есть ошибка, связанная с отличиями между исходным контекстом эмулятора и тем реальным контекстом, который остается после передачи управления твоему коду...
По-видимому, причина неработоспособности заключается в нарушении рекомендации Intel переходить в реальный режим из 32-бит защищенного через 16-бит защищенный... Можно ненароком получить 32-битный реальный режим, в котором DOS/BIOS работать не будет...
спасибо всем за советы, но я кажется разобрался Ж)
проблема в стеке, а точнее в его дескрипторе.
я использовал expand-down тип сегмента, а при смене на нормальный все стало ок..
а вообще щас стал загружать ss селектором дескриптора данных.. так проще.. и легче имхо