Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>There are multiple problems in the code.</p> <p>First, your <code>GDTR.Base</code> contains the offset of the <code>GDT</code> from the beginning of the code since your code is compiled to begin at address 0 (because of <code>org 0</code>). The base address must be the physical address, not a relative address. IOW, if you keep this <code>org 0</code>, you must add <code>CS</code>*16 (=0x7e00) to <code>Base</code>.</p> <p>Second, because of that same <code>org 0</code>, the 32-bit offsets in your code (after <code>bits 32</code> and <code>ProtectedMode:</code>) aren't equal to physical addresses they correspond to, they're 0x7e00 less than the physical addresses. OTOH, the segments defined in your GDT start at physical address 0 (because the base portions of the GDT entries are 0's) and not at 0x7e00. This means that when you try to use these segments with your code/data, you'll be missing the addresses by 0x7e00. If you want to keep <code>org 0</code>, the base addresses in the GDT must be set to 0x7e00.</p> <p>Or you can change <code>org 0</code> to <code>org 0x7e00</code> and then the bases in the GDT should be 0. And you won't need to adjust GDTR.Base by 0x7e00, 0 will do.</p> <p>This should work:</p> <pre><code>bits 16 org 0x7e00 ; loaded at phys addr 0x7e00 ; control must be transferred with jmp 0:0x7e00 xor ax, ax mov ds, ax ; update data segment cli ; clear interrupts lgdt [gdtr] ; load GDT from GDTR (see gdt_32.inc) call OpenA20Gate ; open the A20 gate call EnablePMode ; jumps to ProtectedMode ;****************** ;* Opens A20 Gate * ;****************** OpenA20Gate: in al, 0x93 ; switch A20 gate via fast A20 port 92 or al, 2 ; set A20 Gate bit 1 and al, ~1 ; clear INIT_NOW bit out 0x92, al ret ;************************** ;* Enables Protected Mode * ;************************** EnablePMode: mov eax, cr0 or eax, 1 mov cr0, eax jmp (CODE_DESC - NULL_DESC) : ProtectedMode ;*************** ;* data fields * ;* &amp;includes * ;*************** ;%include "gdt_32.inc" ;********************************* ;* Global Descriptor Table (GDT) * ;********************************* NULL_DESC: dd 0 ; null descriptor dd 0 CODE_DESC: dw 0xFFFF ; limit low dw 0 ; base low db 0 ; base middle db 10011010b ; access db 11001111b ; granularity db 0 ; base high DATA_DESC: dw 0xFFFF ; limit low dw 0 ; base low db 0 ; base middle db 10010010b ; access db 11001111b ; granularity db 0 ; base high gdtr: Limit dw gdtr - NULL_DESC - 1 ; length of GDT Base dd NULL_DESC ; base of GDT ;****************** ;* Protected Mode * ;****************** bits 32 ProtectedMode: mov ax, DATA_DESC - NULL_DESC mov ds, ax ; update data segment .halt: hlt jmp .halt </code></pre> <p>Note that a segment limit equals the segment size minus 1.</p> <p>A few more points... Load all segment registers with valid selectors or 0. Also, set up the stack. If you have garbage there (or old values from real mode), when you start playing with interrupts/exceptions, you'll have more crashes.</p> <p>Finally, I don't know what elf64 is, but you will have to take care of the <code>org</code> thing for other modules and make sure all generated addresses correspond to load addresses. And if you intend to enable 64-bit mode, there's a ton of work to do. I'd advise not to rush into 64-bit mode yet since you're tripping over relatively simple stuff.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload