2016-11-20 8 views
1

Qemu에서 x86 아키텍처에서 페이징을 사용하려고합니다.
그러나이 코드는 트리플 폴트가됩니다.x86 Qemu에서 페이징 사용

이 코드 세그먼트는 보호 모드로 실행됩니다.
코드 : https://github.com/mridulv/simpleOperatingSystem

이 커널 항목이

[bits 32] 

[extern main] 
[extern main2] 
[extern page_table] 

call main 

lea ECX, [page_table - 0xC0000000] 
mov CR3, ECX 

mov ECX, CR0 
or ECX, 0x80000000 
mov CR0, ECX 

;lea ECX, [StartInHigherHalf] 
;jmp ECX 

;StartInHigherHalf: 
; call main2 

jmp $ 

이 페이지 디렉토리, 테이블을 만든 커널 파일을 파일입니다.

unsigned int page_table[1024] __attribute__((aligned(4096)));; 

void set_page_tables() { 
    unsigned int pages_entry[1024 * 1024] __attribute__((aligned(4096))); 

    unsigned int KERNEL_VIRTUAL_OFFSET = 0xC0000000; 
    unsigned int KERNEL_FIRST_VIRTUAL_ADDRESS = 0xC0000000 >> 12; 

    int numPageTables = 4; 
    int numPagesInPageTable = 1024; 
    int numPageTableEntriesInPageDirectory = 1024; 
    int totalPages = numPageTables * numPagesInPageTable; 

    unsigned int index = 0; 
    unsigned int *pages_ptr = (unsigned int *)(pages_entry - KERNEL_VIRTUAL_OFFSET); 
    unsigned int *page_table_ptr = (unsigned int *)(pages_entry - KERNEL_VIRTUAL_OFFSET); 

    unsigned int positionAndFlags = 7; 

    while (index < totalPages) { 
     pages_ptr[index] = positionAndFlags; 
     index = index + 1; 
     positionAndFlags += 4096; 
    } 

    positionAndFlags = 7; 
    index = KERNEL_FIRST_VIRTUAL_ADDRESS; 
    unsigned int totalPagesLeft = KERNEL_FIRST_VIRTUAL_ADDRESS + totalPages; 
    while (index < totalPagesLeft) { 
     pages_ptr[index] = positionAndFlags; 
     index = index + 1; 
     positionAndFlags += 4096; 
    } 

    positionAndFlags = (unsigned int)&pages_ptr[0]; 
    positionAndFlags = positionAndFlags | 7; 
    index = 0; 
    while (index < numPageTableEntriesInPageDirectory) { 
     page_table_ptr[index] = positionAndFlags; 
     index = index + 1; 
     positionAndFlags += 4096; 
    } 
} 

void main() { 
    char* video_memory = (char*) 0xb8000; 
    *video_memory = 'X'; 
    set_page_tables(); 
} 

void main2() { 
    char* video_memory = (char*) 0xb8004; 
    *video_memory = 'Y'; 
    // __asm__ 
    // (
    // "leal (page_table,), %ecx\n\t" // 0xC0000000 = KERNEL_VIRTUAL_BASE 
    // "movl %cr3, %ecx" 
    //); 
} 

Linker.ld

SECTIONS { 
    . = 0xC0100000; 

    .text : AT(ADDR(.text) - 0xC0000000) { 
     *(.text); 
    } 

    . = ALIGN(0x1000); 
    .bss : AT(ADDR(.bss) - 0xC0000000) { 
     *(.text); 
    } 

    . = ALIGN(0x1000); 
    .data : AT(ADDR(.data) - 0xC0000000) { 
     *(.text); 
    } 
} 
+0

명백한 몇 가지. 내가 말할 수있는 [A20 라인] (http://wiki.osdev.org/A20_Line)을 활성화하지 마십시오. 시작시'boot.asm'에서 _DL_ (부팅 드라이브)를 저장 한 다음 데이터 ('PROTECTED_MODE_STR'과'BEGIN_STR')를 바로 뒤에 놓습니다. CPU가 데이터를 실행하려고합니다. 모든 코드 뒤에 데이터를 놓으십시오 (부트 서명 바로 앞의 코드를 이동하십시오). 또 다른 큰 문제는 메모리에 0x1000에 커널을로드한다는 것입니다. 링커 스크립트는'0xC0100000'을 사용합니다. 이것은 커널이 0x100000에로드되었다고 가정하지만 0x1000에 있습니다. 그래서 당신의 경우에는'0xC0001000'이 필요할 수도 있습니다. –

+0

나는 그걸 보지 못했습니다. 그러나 페이징을 사용하려고 시도하기 전에 코드에 도달하기 전에 충분한 문제가 있습니다. –

+0

'lea ECX, [page_table - 0xC0000000]'을'mov ECX, page_table - 0xC0000000'로 변경하는 것도 좋습니다. –

답변

0

내가 분명히 일을하기 위해, 코드의 상단에있는 섹션 선언을 추가 할 조언 것 -

section .text 

및 오류에 실행 전 코드입니다.

call main 

코드에서 ESP 레지스터를 채워 스택을 설정하지 않습니다.

STACK_SIZE equ <valueOfSizeOfStack> 
  • 가 스택

    section .bss 
    kernelStack: RESB <valueOfSizeOfStack> 
    
  • 을위한 공간을 만들기 -

    1. 이 같은 일정 'STACK_SIZE'을 만들기처럼

      이렇게하려면 코드가 있어야한다

      "valueOfSi zeOfStack "필드에 4096 (4KB) 또는 스택을 추가 할 수 있습니다 (크기는 크지 않고 바이너리 크기로 계산됩니다).

    +0

    GitHub에서 CircuitKernel을 검색하여 완전한 커널 예제를 만듭니다. –