Talk:Entering Long Mode Directly

From OSDev.wiki
Latest comment: 13 years ago by Martinro in topic Not to put 64bit code in MBR
Jump to navigation Jump to search

Only put the code that switches you into long mode?

Maybe we shouldn't dump a bootloader here; maybe we put the code to do all of this... Imate900 20:24, 23 April 2009 (UTC)Reply

Version fitting in a single boot sector

Thanks for the code! However, for me, it needed some changes to work: - move the padding and the 0xaa55 signature to the end of the file; this enables the whole example fit in a boot sector, - this eliminates the need for the BIOS 13h call, so I removed it.

My version:


   [ORG 0x00007C00]
   [BITS 16]
    
    
    
   boot_loader:
   ;Parameter from BIOS: dl = boot drive
    
    
   ;Set default state
    
   cli
   xor bx,bx
   mov es,bx
   mov fs,bx
   mov gs,bx
   mov ds,bx
   mov ss,bx
   mov sp,0x7C00
   
   sti
    
   jmp 0:.clear_cs
   .clear_cs:
    
    
   ;Enable A20 via port 92h
    
   in al,92h
   or al,02h
   out 92h,al
    
    
   ;Build page tables
   ;The page tables will look like this:
   ;PML4:
   ;dq 0x000000000000b00f = 00000000 00000000 00000000 00000000 00000000 00000000 10010000 00001111
   ;times 511 dq 0x0000000000000000
    
   ;PDP:
   ;dq 0x000000000000c00f = 00000000 00000000 00000000 00000000 00000000 00000000 10100000 00001111
   ;times 511 dq 0x0000000000000000
    
   ;PD:
   ;dq 0x000000000000018f = 00000000 00000000 00000000 00000000 00000000 00000000 00000001 10001111
   ;times 511 dq 0x0000000000000000
    
   ;This defines one 2MB page at the start of memory, so we can access the first 2MBs as if paging was disabled
    
   ; build the necessary tables
   xor bx,bx
   mov es,bx
   cld
   mov di,0xa000
    
   mov ax,0xb00f
   stosw
   
   xor ax,ax
   mov cx,0x07ff
   rep stosw
    
   mov ax,0xc00f
   stosw
    
   xor ax,ax
   mov cx,0x07ff
   rep stosw
    
   mov ax,0x018f
   stosw
    
   xor ax,ax
   mov cx,0x07ff
   rep stosw
    
    
   ;Enter long mode
    
   mov eax,10100000b				;Set PAE and PGE
   mov cr4,eax
    
   mov edx, 0x0000a000				;Point CR3 at PML4
   mov cr3,edx
    
   mov ecx,0xC0000080				;Specify EFER MSR
    
   rdmsr						;Enable Long Mode
   or eax,0x00000100
   wrmsr
    
   mov ebx,cr0					;Activate long mode
   or ebx,0x80000001				;by enabling paging and protection simultaneously
   mov cr0,ebx					;skipping protected mode entirely
    
   lgdt [gdt.pointer]				;load 80-bit gdt.pointer below
    
   jmp gdt.code:startLongMode			;Load CS with 64 bit segment and flush the instruction cache
    
    
    
   ;Global Descriptor Table
   gdt:
   dq 0x0000000000000000				;Null Descriptor
    
   .code equ $ - gdt
   dq 0x0020980000000000                   
    
   .data equ $ - gdt
   dq 0x0000900000000000                   
    
   .pointer:
   dw $-gdt-1					;16-bit Size (Limit)
   dq gdt						;64-bit Base Address
                           ;Changed from "dd gdt"
                           ;Ref: Intel System Programming Manual V1 - 2.1.1.1
    
    
   [BITS 64]
    
   startLongMode:
    
   cli						;Interupts are disabled because no IDT has been set up
    
   mov edi,0x00b8000				;Display:"Put long mode kernel here.__"
   mov rax,0x0720077407750750                      ;at the top left corner of screen
   mov [edi],rax
   mov rax,0x0767076e076f076c
   mov [edi+8],rax
   mov rax,0x0764076f076d0720
   mov [edi+16],rax
   mov rax,0x0765076b07200765
   mov [edi+24],rax
   mov rax,0x076c0765076e0772
   mov [edi+32],rax
   mov rax,0x0772076507680720
   mov [edi+40],rax
   mov rax,0x07200720072e0765
   mov [edi+48],rax
    
   jmp $						;Hang the system
    
   times 510-($-$$) db 0				;Fill boot sector
   dw 0xAA55					;Boot loader signature
    

To use (in Linux):

   $ nasm -o boot boot.asm
   $ qemu-system-x86_64 -hda boot

Oculusfervoris 06:31, 5 June 2011 (UTC)Reply

Not to put 64bit code in MBR

Oculusfervoris,

Your version is a good example i thinnk, but, there are some problems with the idea of fitting 64bit code into MBR:

  • 64bit code is usually quite large and you won't want to fit a portion

(just a little little section of your code) into a 512byte trunk

  • even you can run 64bit right from MBR, you still have to load more

code from hard disk, and since you can't access BIOS interrupts, problems arise

  • 64bit code is a whole different thing than 16bit, 32bit codes, so

people usually let it start at an even memory address, like being right after MBR (at 7E00h), or wherever else.

--Paul84 11:48, 5 June 2011 (UTC)Reply

This is proof-of-concept code, not an OS kernel or anything like that.Oculusfervoris 15:58, 10 June 2011 (UTC)Reply
I agree. It should be "as minimal as possible" (so that the main concept is shown without any unnecessary stuff in the way); but it should also have warnings saying that it's deliberately "as minimal as possible", potentially including reasons why it's unusable "as is" for an OS (as per Paul84's comments). With this in mind, I'd be tempted to rip out the (unnecessary) "enable A20" code and most of the unnecessary segment loads from Oculusfervoris' version and use that. Brendan 22:43, 10 June 2011 (UTC)Reply
I tried fixing the article - making it as minimal as possible, and even including a example boot sector. --Shikhin 12:38, 10 July 2011 (UTC)Reply

It seems the SS selector must be writable (at least on some CPUs)

My CPU crashed on the "MOV SS,AX" instruction in long mode. I found out the reason was that the section

   .data equ $ - gdt
   dq 0x0000900000000000
             ^

was not writeable in the GDT!!! Changing the code to:

   .data equ $ - gdt
   dq 0x0000930000000000
             ^

resolved the problem. Maybe the code in the article must be changed in this way.

-- Martinro 18:35, 10 November 2011 (UTC)Reply


Setting CR4.PAE before loading CR3

The Intel manual (http://www.intel.com/Assets/ja_JP/PDF/manual/253668.pdf) says on page 4-17:

  • If PAE paging would be in use following an execution of MOV to CR0 or MOV to CR4 (see Section 4.1.1) and the instruction is modifying any of CR0.CD, CR0.NW, CR0.PG, CR4.PAE, CR4.PGE, or CR4.PSE; then the PDPTEs are loaded from the address in CR3
  • If MOV to CR3 is executed while the logical processor is using PAE paging, the PDPTEs are loaded from the address being loaded into CR3.

Since you don't know the current value in CR3, wouldn't it be better to load CR3 before changing CR4 to enable PAE? Else the CPU could e.g. be accessing a non-existing physical memory location