2012-02-06 35 views
5

Tôi đang cố chuyển sang chế độ được bảo vệ trong x86 intel."gọi" sau khi chuyển sang Chế độ được bảo vệ

Tôi đã nạp GDT của tôi với lgdt, đặt cờ P của cr0 đến 1 và tất cả các phân đoạn selectors nhưng khi tôi trở về từ cuộc gọi chức năng, tôi không thể gọi bất kỳ chức năng khác hoặc tôi nhận được lỗi này

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

đây là chức năng của tôi switch_to_pmode:

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 

Và các cuộc gọi của tôi

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

Thank bạn

Trả lời

3

Bạn cần đảm bảo rằng trình biên dịch dịch mã theo công tắc chế độ được bảo vệ thành mã 32 bit, với chỉ thị .code32 (hoặc use32 trong nasm).

Ngoài ra địa chỉ trả lại của bạn sau khi thói quen chế độ được bảo vệ không còn hợp lệ. Bạn không thể trở lại bất cứ điều gì sau đó. Thay vào đó, hãy đặt esp thành một cái gì đó hữu ích và tiếp tục.

+0

Cảm ơn bạn! Các .code32 hoạt động! – marmottus

3

Việc di chuyển đến CR0 đặt hoặc xóa PE phải là ngay lập tức, sau đó là tải lại máy tính và sau đó bạn phải tải lại %esp cũng như tất cả thanh ghi phân đoạn. Bạn cần phải thực hiện tất cả các điều này trước khi bạn chạm vào ngăn xếp hoặc bật ngắt. Và (như drhirsch nói) không thể trả lại từ thao tác này, ngay cả khi bạn bật địa chỉ trả về trước khi bạn vô hiệu hóa ngăn xếp chế độ thực, vì địa chỉ trả về là địa chỉ chế độ thực.

Có vẻ như bạn đang cố gắng sử dụng lret để tải lại PC và đồng thời bật lại ngắt, nhưng điều đó sẽ không hoạt động vì con trỏ ngăn xếp không hợp lệ. mã đúng sẽ giống như thế này:

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 

Bạn nên đọc, đặc biệt là chương 9 (máy khởi) của system programming guide Intel, đặc biệt phần 9.9, trong đó mô tả một cách chi tiết làm thế nào để làm một công tắc chế độ bảo vệ.

+0

AFAIK miễn là không có bước nhảy xa nào được thực hiện, CPU vẫn hoạt động ở chế độ thực. Tôi đọc 'đẩy $ 8; đẩy reload_segments; retl' như một cách sáng tạo để thực hiện một bước nhảy xa. Nhưng cách bạn mô tả là cách kinh điển và nó hoạt động đáng tin cậy theo cách đó. – hirschhornsalz

+1

Đó là sáng tạo, nhưng nó không được đảm bảo để hoạt động - hướng dẫn sử dụng kiến ​​trúc khá rõ ràng: "Ngay lập tức làm theo hướng dẫn MOV CR0, thực hiện lệnh JMP hoặc CALL xa. ... Lỗi ngẫu nhiên có thể xảy ra nếu * các lệnh khác tồn tại * giữa [các hướng dẫn này]. " (nhấn mạnh mỏ) ([Sách hướng dẫn của Nhà phát triển Phần mềm Kiến trúc Intel® 64 và IA-32 Tập 3: Hướng dẫn Lập trình Hệ thống] (http://www.intel.com/content/dam/doc/manual/64-ia-32-architectures -software-developer-system-programming-manual-325384.pdf), phần 9.9) – zwol

Các vấn đề liên quan