2015-01-16 6 views
1

매우 간단한 부트 로더에서 보호 모드로 실행하기 전에 데이터 세그먼트 (ds)에 무언가를 할당하면 프로세서 오류가 발생한다는 것을 발견했습니다.데이터 세그먼트가 0이 아니면 보호 모드가 실패합니다

이 코드는 잘 작동합니다 :

[BITS 16] 
[ORG 0x7c00] 

xor ax,ax 
mov ds,ax 

cli 
lgdt [gdt_descriptor] 

mov eax, cr0  
or eax,1    
mov cr0, eax 

jmp CODE_SEG:now 

[BITS 32] 
now: 
    jmp $ 

    db 0 
gdt_start: 
gdt_null: 
    dd 0x0 
    dd 0x0 
gdt_cs: 
    dw 0xFFFF ; Limit 
    dw 0x0000 ; Base 
    db 0x0000 ; Base 23:16 
    db 10011011b 
    db 11011111b 
    db 0x0000 
gdt_ds: 
    dw 0xFFFF ; Limit 
    dw 0x0000 ; Base 
    db 0x0000 ; Base 23:16 
    db 10010011b 
    db 11011111b 
    db 0x0000 
gdt_end 
gdt_descriptor: 
    dw gdt_end - gdt_start - 1 
    dd gdt_start 

CODE_SEG equ gdt_cs - gdt_start 
DATA_SEG equ gdt_ds - gdt_start 

times 510-($-$$) db 0 ; fill sector w/ 0's 
db 0x55   ; req'd by some BIOSes 
db 0xAA 

이것은 하나의 프로세서를 다시 시작합니다 :

[BITS 16] 
[ORG 0x7c00] 

mov ax,0x10 ;<-- Pre-assigning data segment 
mov ds,ax 

cli 
lgdt [gdt_descriptor] 

mov eax, cr0  
or eax,1    
mov cr0, eax 

jmp CODE_SEG:now 

[BITS 32] 
now: 
    jmp $ 

    db 0 
gdt_start: 
gdt_null: 
    dd 0x0 
    dd 0x0 
gdt_cs: 
    dw 0xFFFF ; Limit 
    dw 0x0000 ; Base 
    db 0x0000 ; Base 23:16 
    db 10011011b 
    db 11011111b 
    db 0x0000 
gdt_ds: 
    dw 0xFFFF ; Limit 
    dw 0x0000 ; Base 
    db 0x0000 ; Base 23:16 
    db 10010011b 
    db 11011111b 
    db 0x0000 
gdt_end 
gdt_descriptor: 
    dw gdt_end - gdt_start - 1 
    dd gdt_start 

CODE_SEG equ gdt_cs - gdt_start 
DATA_SEG equ gdt_ds - gdt_start 

times 510-($-$$) db 0 ; fill sector w/ 0's 
db 0x55   ; req'd by some BIOSes 
db 0xAA 

나는 NASM과 함께이 컴파일 내가 VM웨어와 함께 달렸다.

왜 이런 일이 발생합니까?

+0

'ds'를 잘못된 값으로로드하고 있습니다. 왜 그것이 작동하기를 기대합니까? –

+0

여기서 문서는 ds가 보호 모드를로드하는 긴 점프 전에 0이 아니어야한다고 지정합니다. 그 외에도 0x10은 올바른 값입니다. 보호 모드로 점프 한 후 0x10으로 ds를 설정하면 정상적으로 작동합니다. – felknight

+0

@ Felipe : Jonathon의 대답은 정확합니다. 그러나 당신이 지금 가지고있는 하나의 특정한 문제에 대해서만 접촉합니다. 잘못된 정보 ("ds는 점프 전에 0이 아니어야합니다.")에 의존하는 것을 비롯하여 실제 모드 세그먼트로드와 보호 모드 세그먼트로드 사이의 차이점을 이해하지 못하고 BIOS가 특정 상태로 특정 레지스터를 남겨 둔다고 잘못 가정합니다 부트 로더의 처음 512 바이트에서 보호 모드로 전환하더라도 설계상의 실수입니다. – Brendan

답변

2

보호 모드로 들어가기 전에 ds을 설정하는 것이 문제가 아닙니다. 문제는 lgdt 명령어를 실행하기 전에 ds을 설정한다는 것입니다.

lgdt 명령은 데이터 세그먼트의 메모리에도 액세스하므로 명령을 실행할 때 ds이 올바른 값이어야합니다. ds을 변경하면로드하려는 GDT의 실제 주소가 변경되었습니다. 그런 다음 해당 GDT에 cs 세그먼트가있는 보호 모드를 시작하면 GDT 항목이 가짜이며 프로세서가 예외를 생성했습니다. 마지막으로, 아직 IDT를 설정하지 않았기 때문에 프로세서가 이중화 된 다음 트리플 폴트되고 재부팅됩니다.

gdt_descriptor이 코드에 0x40 바이트라고 가정 해 봅시다. 즉, 부트 로더가로드 될 때 0000:7C40에 있음을 의미합니다. ds이 0 일 때 lgdt [gdt_descriptor] 명령어는 기본/한계 인 (0x0 << 4) + 0x7C40 == 0x7C40에서 GDT를로드하려고 시도합니다. 그러나 ds0x10으로 설정하면 기본/제한 인 (0x10 << 4) + 0x7C40 == 0x7D40에서 GDT를로드하려고합니다. 의도하지 않은 것입니다.

보호 모드로 들어가기 전에 ds에서 0x10으로 설정할 수 있습니다. PM에 뛰어들 때까지는 메모리 액세스 (예 : lgdt)를하지 마십시오.