title: Entering Long Mode
body: <p>I have been working on a bootloader and am currently trying to get it to switch to long mode. I have already switched to protected mode so far and I am certain it works, but it seems like when I enable paging to enter long mode it causes a fault. I think it might be because of my page table. Here is the code:</p>
  
  <pre><code>[BITS 16] 
  org 0x2000 
  
  Start: 
  
   jmp  main 
  
  ;Constants
  
  %DEFINE TEAL 0x03 
  %DEFINE RED 0x04 
  %DEFINE PURPLE 0x05 
  %DEFINE VIDEO_MEM 0xB8000 
  %DEFINE COLS    80                      ; width and height of screen 
  %DEFINE LINES   25 
  %DEFINE LONG_SELECTOR  3 &lt;&lt; 3 
  
  X_POS:  db 0 
  Y_POS:  db 0 
  
  ;Enabling the A20 line
  
  EnableA20: 
  
      IN AL, 0x92         ; A20, using fast A20 gate 
      MOV CL, AL 
      AND CL, 2 
      JNZ .skip            ; if a20 bit seems set, don't touch it 
      OR AL, 2 
      OUT 0x92, AL 
      .skip: 
  
  ret 
  
  main:            
  ;first stage of bootloader is loaded at the address 0x07c0:0 
  ;second stage of bootloader is loaded at address 0x200:0x0 
  
     cli 
     xor ax, ax         ; All segments set to 0, flat memory model 
     mov ds, ax 
     mov es, ax 
     mov gs, ax 
     mov fs, ax 
     mov ss, ax 
  
     ; Set stack top SS:0xffff 
  
     mov sp, 0x0FFFF 
  
          mov [CDDriveNumber], dl 
  
          SwitchToProtectedMode: 
  
          lgdt [GDT_32];load the gdt 
          call EnableA20 
  
          mov eax, cr0 
          or eax, 1 
          mov cr0, eax 
  
           ; Flush CS and set code selector 
          jmp 0x8:Protected_Mode 
  
          [BITS 32];Declare 32 bits 
  
          Protected_Mode: 
  
          mov eax,0x10    ; load 4 GB data descriptor
          mov ds,ax           ; to all data segment registers
          mov es,ax
          mov fs,ax
          mov gs,ax
          mov ss,ax
  
          mov eax,cr4
          or  eax,1 &lt;&lt; 5
          mov cr4,eax         ; enable physical-address extensions
  
          mov edi,70000h
          mov ecx,4000h &gt;&gt; 2
          xor eax,eax
          rep stosd           ; clear the page tables
  
          mov dword [70000h],71000h + 111b ; first PDP table
          mov dword [71000h],72000h + 111b ; first page directory
          mov dword [72000h],73000h + 111b ; first page table
  
          mov edi,73000h      ; address of first page table
          mov eax,0 + 111b
          mov ecx,256         ; number of pages to map (1 MB)
      make_page_entries:
          stosd
          add edi,4
          add eax,1000h
          loop    make_page_entries
  
          mov eax,70000h
          mov cr3,eax         ; load page-map level-4 base
  
          mov ecx,0C0000080h      ; EFER MSR
          rdmsr
          or  eax,1 &lt;&lt; 8      ; enable long mode
          wrmsr
  
          lgdt[GDT_64]
  
          mov eax,cr0       ; &lt;&lt;  problem here 
          or  eax,1 &lt;&lt; 31
          mov cr0,eax         ; enable paging
  
          jmp 0x08:Long_Mode 
          [BITS 64] 
  
  
          Long_Mode:
  
          call clear 
          xor bx, bx 
          mov bx, Entered_LMODE 
          call sPrint 
  
          cli 
          hlt 
          [BITS 32] 
          clear: 
  
          pusha 
          mov edi, VIDEO_MEM 
          mov BYTE[edi], ' ' 
          mov BYTE[edi+1], TEAL
          rep stosw 
          MOV BYTE[X_POS], 0x0 
          MOV BYTE [Y_POS], 0x0 
          popa 
          ret 
  
          sPrint: 
          pusha 
                  jmp .start 
                  .Row: 
                  call NewLine 
                  MOV BYTE[EDI], ' ' 
                  jmp .Next 
                  .start: 
                  MOV EDI, VIDEO_MEM 
                  xor ecx, ecx 
                  xor eax, eax 
                  mov     ecx, COLS*2             ; Mode 7 has 2 bytes per char, so its COLS*2 bytes per line 
                  mov     al, BYTE [Y_POS]        ; get y pos 
                  mul     ecx                     ; multiply y*COLS 
                  push    eax                     ; save eax--the multiplication 
  
                  mov     al, byte [X_POS]        ; multiply _CurX by 2 because it is 2 bytes per char 
                  mov     cl, 2 
                  mul     cl 
                  pop     ecx                     ; pop y*COLS result 
                  add     eax, ecx 
  
                  add edi, eax 
                  mov al,BYTE[bx] 
  
                  cmp al, 0x0;check if end 
                  je .Done 
                  cmp al, 0xA;check if new line 
                  je .Row 
  
                  mov BYTE[edi],al  
                  .Next: 
                  mov BYTE[edi+1], PURPLE
                  INC BX 
                  inc     BYTE[X_POS]             ; go to next character 
                  cmp     BYTE[X_POS], COLS               ; are we at the end of the line? 
                  je      .Row                    ; yep-go to next row 
  
  
                  jmp .start 
          .Done: 
  
          popa 
  
          ret 
          NewLine: 
          inc BYTE[Y_POS] 
          MOV BYTE[X_POS], -1 
  
          ret 
  Entered_PMODE:  db "You have succcessfully entered Protected Mode Very Happy",0xA, 0 
  LOAD_SUCCESS:   db "Stage 2 Loaded Successfully",0xA, 0 
  CDDriveNumber:  db 0 
  Entered_LMODE:  db "You have successfully entered Long Mode Very Happy !!!!!!!!!!!",0xA,0 
  
  
  GDT_START: 
  ;null descriptor 
  dd 0 
  dd 0 
  ;data descriptor 
  dw 0xFFFF 
  dw 0 
  db 0 
  db 10011010b 
  db 11001111b 
  db 0 
  ;code descriptor 
  dw 0xFFFF 
  dw 0 
  db 0 
  db 10010010b 
  db 11001111b 
  db 0 
  GDT_END: 
  align 4 
  GDT_32: 
  dw GDT_END - GDT_START - 1 
  dd GDT_START 
  
  GDT_64: 
  .Null: 
      dq 0x0000000000000000             ; Null Descriptor - should be present. 
  
  .Code_64: 
      dq 0x0020980000000000             ; 64-bit code descriptor.  
      dq 0x0000900000000000             ; 64-bit data descriptor.  
  .Pointer: 
      dw $ - GDT_64 - 1                    ; 16-bit Size (Limit) of GDT. 
      dd GDT_64                            ; 32-bit Base Address of GDT. (CPU will zero extend to 64-bit) 
  
  ALIGN 4 
  IDT: 
      .Length       dw 0 
      .Base         dd 0 
  
  PML4_POINTER:;blank table 
          dd 0                                                                             
  PML4_POINTER_END: 
  table_768: dd 0 
  </code></pre>