GRUB2 Higher-Half 64 Bit

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
inixsoftware
Member
Member
Posts: 32
Joined: Fri Jan 31, 2014 8:21 am

GRUB2 Higher-Half 64 Bit

Post by inixsoftware »

I am trying to adapt the Higher-Half Bare Bones tutorial for 64 bit (by making it switch into compatibility mode of long mode & then load a 64bit GDT). So, first I am just compiling the code verbatim using a 64 bit GCC and NASM (with -felf64).

I added the [BITS 32] directive to the Assembly source and I assembled & linked. I generate a bootable iso, and launch QEMU. When GRUB2 begins to load the OS, it complains that the "entry point isn't in a segment".

Why exactly is this happening? I looked at the article and it does mention that "entry point isn't in a segment" would happen if _loader was the entry-point instead of loader, however, I did not make modifications, so, that shouldn't be an issue...
dschatz
Member
Member
Posts: 61
Joined: Wed Nov 10, 2010 10:55 pm

Re: GRUB2 Higher-Half 64 Bit

Post by dschatz »

Post linker script and assembly, also grub version
naegelejd
Posts: 12
Joined: Thu Oct 09, 2014 5:09 pm

Re: GRUB2 Higher-Half 64 Bit

Post by naegelejd »

I have the same issue with grub-mkrescue 2.02~beta (compiled from grub Git repo). I am using the 32-bit Higher Half bare bones. This code worked a year ago. I will try an older version of Grub 2, but in the meantime:

link.ld:

Code: Select all

OUTPUT_FORMAT(elf32-i386)
ENTRY(load)

phys = 0x100000;
offset = 0xC0000000;
virt = offset + phys;

SECTIONS
{
    . = virt;
    .text : AT(ADDR(.text) - offset) {
        g_code = .;
        *(.text)
        *(.rodata)
        . = ALIGN(0x1000);
    }
    .data : AT(ADDR(.data) - offset) {
        g_data = .;
        *(.data)
        . = ALIGN(0x1000);
    }
    .bss : AT(ADDR(.bss) - offset) {
        g_bss = .;
        *(COMMON)
        *(.bss)
        . = ALIGN(0x1000);
    }
    g_end = .;
    /DISCARD/ : {
        *(.comment)
        *(.eh_frame)
        *(.note.gnu.build-id)
    }
}
start.s:

Code: Select all

bits 32

; Definitions
KERNEL_CS equ 0x08
KERNEL_DS equ 0x10
USERMODE_CS equ 0x18
USERMODE_DS equ 0x20

STACK_SIZE          equ 0x1000 ; 4KB stack
THREAD_CONTEXT_SIZE equ 0x1000 ; 4KB just for thread struct

MBOOT_PAGE_ALIGN    equ 0x1
MBOOT_MEM_INFO      equ 0x2
MBOOT_USE_GFX       equ 0x4
MBOOT_HDR_MAGIC     equ 0x1BADB002
MBOOT_HDR_FLAGS     equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO
MBOOT_CHECKSUM      equ -(MBOOT_HDR_MAGIC + MBOOT_HDR_FLAGS)

; 3GB offset for translating physical to virtual addresses
KERNEL_VIRTUAL_BASE equ 0xC0000000
; Page directory idx of kernel's 4MB PTE
KERNEL_PAGE_NUM     equ (KERNEL_VIRTUAL_BASE >> 22)

section .data
align 0x1000
; This PDE identity-maps the first 4MB of 32-bit physical address space
; bit 7: PS - kernel page is 4MB
; bit 1: RW - kernel page is R/W
; bit 0: P  - kernel page is present
boot_page_directory:
    dd 0x00000083   ; First 4MB, which will be unmapped later
    times (KERNEL_PAGE_NUM - 1) dd 0    ; Pages before kernel
    dd 0x00000083   ; Kernel 4MB at 3GB offset
    times (1024 - KERNEL_PAGE_NUM - 1) dd 0 ; Pages after kernel


section .text
align 4
; start of kernel image:
; Multiboot header
; note: you don't need Multiboot AOUT Kludge for an ELF kernel
multiboot:
    dd MBOOT_HDR_MAGIC
    dd MBOOT_HDR_FLAGS
    dd MBOOT_CHECKSUM
    ; Mem info (only valid if aout kludge flag set or ELF kernel)
    ;dd 0x00000000   ; header address
    ;dd 0x00000000   ; load address
    ;dd 0x00000000   ; load end address
    ;dd 0x00000000   ; bss end address
    ;dd 0x00000000   ; entry address
    ; Graphics requests (only valid if graphics flag set)
    ;dd 0x00000000   ; linear graphics
    ;dd 0            ; width
    ;dd 0            ; height
    ;dd 32           ; set to 32


global load
load equ (g_start - KERNEL_VIRTUAL_BASE)

extern kmain
global g_start
g_start:
    mov ecx, (boot_page_directory - KERNEL_VIRTUAL_BASE)
    mov cr3, ecx    ; Load page directory

    mov ecx, cr4
    or ecx, 0x00000010  ; Set PSE bit in CR4 to enable 4MB pages
    mov cr4, ecx

    mov ecx, cr0
    or ecx, 0x80000000  ; Set PG bit in CR0 to enable paging
    mov cr0, ecx

    ; EIP currently holds physical address, so we need a long jump to
    ; the correct virtual address to continue execution in kernel space
    lea ecx, [start_higher_half]
    jmp ecx     ; Absolute jump!!

start_higher_half:
    ; Unmap identity-mapped first 4MB of physical address space
    mov dword [boot_page_directory], 0
    invlpg [0]

    mov esp, kernel_stack_top ; set up stack pointer
    push eax    ; push header magic
    add ebx, KERNEL_VIRTUAL_BASE    ; make multiboot header pointer virtual
    push ebx    ; push header pointer (TODO: hopefully this isn't at an addr > 4MB)
    cli         ; disable interrupts
    call kmain
User avatar
sortie
Member
Member
Posts: 931
Joined: Wed Mar 21, 2012 3:01 pm
Libera.chat IRC: sortie

Re: GRUB2 Higher-Half 64 Bit

Post by sortie »

That tutorial is disputed. Don't rely on it.

I really should delete the million higher half tutorials from the wiki (or stash them somewhere they don't seem desirable). They are all subtly or not-so-subtly broken.
naegelejd
Posts: 12
Joined: Thu Oct 09, 2014 5:09 pm

Re: GRUB2 Higher-Half 64 Bit

Post by naegelejd »

To clarify, I'm using the 32-bit Higher Half Bare Bones tutorial, which may also be disputed (but no doubt widely-used), but QEMU has no problem loading my elf kernel. The issue seems to be with Grub 2 loading my kernel.
Post Reply