2012-02-06 4 views
5

Intel x86에서 보호 모드로 전환하려고합니다.보호 모드로 전환 한 후 "호출"

내가 lgdt 내 GDT를로드 한 1에 CR0의 P 플래그를 설정하고 난 함수 호출에서 돌아 왔을 때 모든 세그먼트 셀렉터는하지만, 내가 다른 함수를 호출 할 수 없거나 나는이 오류가

gdtr: 
.short  23 // limit 
gdtr_base: 
.long  0 // base 

switch_to_pmode: 
    movl $null_segment, %eax  // Address of the first byte of the GDT 
    movl %eax, gdtr_base 

    cli    // disable interrupts 

    lgdt (gdtr) 

    movl %cr0, %eax 
    or $0x1, %eax 
    movl %eax, %cr0   // Set the PE flag 

    push $0x8 
    push $reload_segments 
    lret 

reload_segments: 
    movl $0x10, %eax 
    movl %eax, %ds 
    movl %eax, %ss 
    movl %eax, %es 
    movl %eax, %fs 
    movl %eax, %gs 

    ret 

foo: 
    ret 

그리고 내 전화

_start: 
    call switch_to_pmode 
    call foo // <----- Ouch! 

감사 : 여기

qemu: fatal: Trying to execute code outside RAM or ROM at 0xfeeb7c5b 

내 switch_to_pmode 기능입니다 당신

답변

3

.code32 (또는 nasm에서 use32) 지시문이있는 어셈블러가 보호 모드 스위치 다음의 코드를 32 비트 코드로 변환하는지 확인해야합니다.

또한 보호 모드 루틴 후 반환 주소는 더 이상 유효하지 않습니다. 당신은 그 후에 무엇이든에 진짜로 돌려 보낸다. 대신 esp를 유용한 것으로 설정하고 계속 진행하십시오.

+0

고마워요! .code32가 작동합니다! – marmottus

3

설정 또는 PE가 즉시 멀리 점프 다음는 PC를 다시로드해야 클리어 한 다음 %esp뿐만 아니라 모든 세그먼트 레지스터를 다시로드해야합니다 CR0에 대한 이동합니다. 전에 전에 스택을 만지거나 인터럽트를 활성화해야합니다. 그리고 반환 주소가 리얼 모드 주소이므로 리얼 모드 스택을 무효화하기 전에 반송 주소를 팝하는 경우에도 을 반환 할 수 없습니다 (drhirsch).

lret을 사용하여 PC를 다시로드하고 동시에 인터럽트를 다시 사용하려고했으나 스택 포인터가 유효하지 않기 때문에 작동하지 않습니다. 올바른 코드는 다음과 같을 것이다 :

switch_to_pmode: 
    # ... what you have ... 

    movl %eax, %cr0 
.code32 
    ljmpl reload_segments 

reload_segments: 
    # ... what you have ... 
    movl $pm_stack, %esp 
    sti # perhaps 

    # and then just go on with your startup code here 
    call foo 

당신은 자세히 설명 인텔의 system programming guide, 특히 제 9 장 (기계 초기화), 특히 섹션 9.9은 보호 모드 스위치를 수행하는 방법을 읽어야합니다.

+0

AFAIK 먼 점프가 실행되지 않는 한 CPU는 여전히 리얼 모드로 작동합니다. 나는'push $ 8;을 읽었다. 푸시 reload_segments; 멀리뛰기를 실행하는 창조적 인 방법으로 'retl'. 그러나 당신이 묘사하는 방식은 정식 방식이며 신뢰할 수있는 방식으로 작동합니다. – hirschhornsalz

+1

창의적이지만 작동 보장되지는 않습니다. 아키텍처 설명서는 매우 명확합니다. "MOV CR0 명령 바로 다음에 멀리있는 JMP 또는 원거리 CALL 명령을 실행하십시오. * 다른 명령이있을 경우 임의의 오류가 발생할 수 있습니다 * 사이 [이 지침]. " (강조 광산) ([인텔 ® 64 및 IA-32 아키텍처 소프트웨어 개발자 설명서 볼륨 3 : 시스템 프로그래밍 안내서] (http://www.intel.com/content/dam/doc/manual/64-ia-32-architectures -software-developer-system-programming-manual-325384.pdf), 9.9 절) – zwol