2017-03-14 66 views
2

另一个切换到32位保护模式问题。我目前正在编写一个安全的操作系统(仅用于文本),并且已经研究了关于切换模式的教程,但是我错过了一些东西,或者列出的代码并没有包含所有的细节。我有一个简单的启动加载器加载这段代码然后运行它。此代码然后将加载内核并可能切换到64位长模式。代码错误在mov cr0,eax行。我真的很难过,所以真的很感谢有人看一看。如果有帮助,我跑它作为一个的VirtualBox虚拟机并在调试它与故障“U32:错误:DBGCCmdHlpVarToDbgfAddr失败的‘0000:00009362升的’:VERR_INVALID_SELECTOR”当我尝试反汇编。代码必须从别人那里借来的一些部分,因此我试图在那里我可以承认这一点。X86切换到32位保护模式

;; 
;; enableA20.s (adapted from Visopsys OS-loader) 
;; 
;; Copyright (c) 2000, J. Andrew McLaughlin 
;; You're free to use this code in any manner you like, as long as this 
;; notice is included (and you give credit where it is due), and as long 
;; as you understand and accept that it comes with NO WARRANTY OF ANY KIND. 
;; Contact me at [email protected] about any bugs or problems. 
;; 
org 0x9210 

enableA20: 
;; This subroutine will enable the A20 address line in the keyboard 
;; controller. Takes no arguments. Returns 0 in EAX on success, 
;; -1 on failure. Written for use in 16-bit code, see lines marked 
;; with 32-BIT for use in 32-bit code.u 9210 

[BITS 16] 

mov bx,jumper 
call prstr 

pusha 

;; Make sure interrupts are disabled 
cli 

;; Keep a counter so that we can make up to 5 attempts to turn 
;; on A20 if necessary 
mov CX, 5 

.startAttempt1:  
;; Wait for the controller to be ready for a command 
.commandWait1: 
xor AX, AX 
in AL, 64h 
bt AX, 1 
jc .commandWait1 

;; Tell the controller we want to read the current status. 
;; Send the command D0h: read output port. 
mov AL, 0D0h 
out 64h, AL 

;; Wait for the controller to be ready with a byte of data 
.dataWait1: 
xor AX, AX 
in AL, 64h 
bt AX, 0 
jnc .dataWait1 

;; Read the current port status from port 60h 
xor AX, AX 
in AL, 60h 

;; Save the current value of (E)AX 
push AX   ; 16-BIT 
;; push EAX  ; 32-BIT 

;; Wait for the controller to be ready for a command 
.commandWait2: 
in AL, 64h 
bt AX, 1 
jc .commandWait2 

;; Tell the controller we want to write the status byte again 
mov AL, 0D1h 
out 64h, AL 

;; Wait for the controller to be ready for the data 
.commandWait3: 
xor AX, AX 
in AL, 64h 
bt AX, 1 
jc .commandWait3 

;; Write the new value to port 60h. Remember we saved the old 
;; value on the stack 
pop AX   ; 16-BIT 
;; pop EAX  ; 32-BIT 

;; Turn on the A20 enable bit 
or AL, 00000010b 
out 60h, AL 

;; Finally, we will attempt to read back the A20 status 
;; to ensure it was enabled. 

;; Wait for the controller to be ready for a command 
.commandWait4: 
xor AX, AX 
in AL, 64h 
bt AX, 1 
jc .commandWait4 

;; Send the command D0h: read output port. 
mov AL, 0D0h 
out 64h, AL 

;; Wait for the controller to be ready with a byte of data 
.dataWait2: 
xor AX, AX 
in AL, 64h 
bt AX, 0 
jnc .dataWait2 

;; Read the current port status from port 60h 
xor AX, AX 
in AL, 60h 

;; Is A20 enabled? 
bt AX, 1 

;; Check the result. If carry is on, A20 is on. 
jc .success 

;; Should we retry the operation? If the counter value in ECX 
;; has not reached zero, we will retry 
loop .startAttempt1 


;; Well, our initial attempt to set A20 has failed. Now we will 
;; try a backup method (which is supposedly not supported on many 
;; chipsets, but which seems to be the only method that works on 
;; other chipsets). 


;; Keep a counter so that we can make up to 5 attempts to turn 
;; on A20 if necessary 
mov CX, 5 

.startAttempt2: 
;; Wait for the keyboard to be ready for another command 
.commandWait6: 
xor AX, AX 
in AL, 64h 
bt AX, 1 
jc .commandWait6 

;; Tell the controller we want to turn on A20 
mov AL, 0DFh 
out 64h, AL 

;; Again, we will attempt to read back the A20 status 
;; to ensure it was enabled. 

;; Wait for the controller to be ready for a command 
.commandWait7: 
xor AX, AX 
in AL, 64h 
bt AX, 1 
jc .commandWait7 

;; Send the command D0h: read output port. 
mov AL, 0D0h 
out 64h, AL 

;; Wait for the controller to be ready with a byte of data 
.dataWait3: 
xor AX, AX 
in AL, 64h 
bt AX, 0 
jnc .dataWait3 

;; Read the current port status from port 60h 
xor AX, AX 
in AL, 60h 

;; Is A20 enabled? 
bt AX, 1 

;; Check the result. If carry is on, A20 is on, but we might warn 
;; that we had to use this alternate method 
jc .warn 

;; Should we retry the operation? If the counter value in ECX 
;; has not reached zero, we will retry 
loop .startAttempt2 


;; OK, we weren't able to set the A20 address line. Do you want 
;; to put an error message here? 
jmp .fail 


.warn: 
;; Here you may or may not want to print a warning message about 
;; the fact that we had to use the nonstandard alternate enabling 
;; method 
mov bx,a20alt 
call prstr 
.success: 
sti 
popa 
xor AX, AX 
mov bx,a20norm 
call prstr 
jmp loader 

.fail: 
sti 
popa 
mov AX, -1 
mov bx,a20err 
call prstr 
hlt 
ret 


; 
; Prints string to screen 
; 
prstr: 
push bx 
mov ah,0x0E 
ploop: 
mov al,[bx]    ;load byte of string 
cmp al,0    ;if al=0 then string has ended so return 
jz fin 
mov bh,0 
mov bl,7 
int 0x10    ;print chr in string 
pop bx 
inc bx 
push bx 
jmp ploop    ;back to print next chr 
fin: 
pop bx     ;get bx off stack 
ret 

section .data 

a20err:    db 13,10,13,10,"A20 initialisation failed, halting",0 
a20alt:    db 13,10,13,10,"Alternate A20 switch",0 
a20norm:   db 13,10,13,10,"Normal A20 switch",0 
jumper:    db 13,10,13,10,"Jumped to code",0 



loader: 

; 
;jump to 32bit mode next 
; 
;32 bit mode code and gdt with help from Broken Thorn Website 
;OS tutorial by Mike 
; 

cli    ; clear interrupts 
xor ax,ax 
mov ds,ax 
[BITS 32] 

lgdt [toc]   ; load GDT into GDTR 
mov eax, cr0  ; set bit 0 in cr0--enter pmode 
or eax, 1 
mov cr0, eax 
jmp $ 
mov ax, DATA_SEG 
mov ds, ax 
mov es, ax 
mov fs, ax 
mov gs, ax 
mov ss, ax  
mov esp, 0x090000 ; Set stack to grown downwards from 0x30000 
jmp 0x08:clear_prefetch 
nop 
nop 
clear_prefetch: 

;;mov ax,cs  ; 
;;push ax   ; 
;;mov eax,Really32 ; 
;;push eax   ; 
;;retf   ; 

jmp 0x08:Really32 


Really32: 

; 
;test 32 bit mode 
; 

mov eax,0xb8000 
mov word [Eax],0x41 
jmp $ 








; 
;GDT table 
; Offset 0 in GDT: Descriptor code=0 
; 
;First 1gb for code and then the rest for Data 
; 


gdt_data: 
dd 0    ; null descriptor 
dd 0 

; Offset 0x8 bytes from start of GDT: Descriptor code therfore is 8 

; gdt code:    ; code descriptor 
gdt_code: 
dw 0FFFFh   ; limit low 
dw 0    ; base low 
db 0     ; base middle 
db 10011010b   ; access 
db 11001111b   ; granularity = Limit = 2GB-1 
db 00    ; base high = Base =1GB 

; Offset 16 bytes (0x10) from start of GDT. Descriptor code therfore is 0x10. 

; gdt data:    ; data descriptor 
gdt_dat: 
dw 0FFFFh   ; limit low 
dw 0    ; base low 
db 0    ; base middle 
db 10010010b   ; access 
db 11001111b   ; granularity = limit=rest of memry for data 
db 00    ; base high 

;...Other descriptors begin at offset 0x18. Remember that each descriptor is 8 bytes in size? 
; Add other descriptors for Ring 3 applications, stack, whatever here... 

end_of_gdt: 
toc: 
dw end_of_gdt - gdt_data ; limit (Size of GDT) 
dd gdt_data    ; base of GDT 

CODE_SEG equ gdt_code - gdt_data 
DATA_SEG equ gdt_dat - gdt_data 

最后几行代码应该在屏幕上写'A'。 问候

Bipman

+0

您是否试图单步执行调试器中的代码? –

+0

为什么在进入PM之前有'[BITS 32] * *? –

+0

我加载调试器时VM崩溃 – Bipman

回答

0

感谢玛格丽特我在移动的答案[比特32],也产生远跳为一系列字节,而不是使用32位的远跳这当然不工作。希望64位长模式不是这个混淆!下面的代码。

lgdt [toc]   ; load GDT into GDTR 
mov eax, cr0  ; set bit 0 in cr0--enter pmode 
or eax, 1 
mov cr0, eax 
jmp clear_prefetch 
nop 
nop 
clear_prefetch: 
mov ax, DATA_SEG 
mov ds, ax 
mov es, ax 
mov fs, ax 
mov gs, ax 
mov ss, ax 
mov esp, 0x090000 ; Set stack to grown downwards from 0x30000 

;;mov ax,cs  ; 
;;push ax   ; 
;;mov eax,Really32 ; 
;;push eax   ; 
;;retf   ; 

db 0x66 
db 0xEA 
dd Really32 
dw 0x0008 


Really32: 

; 
;test 32 bit mode 
; 
[BITS 32] 

mov eax,0xb8000 
mov word [Eax],0x4141 
jmp $ 
相关问题