Page 1 of 1

GRUB2 Higher-Half 64 Bit

Posted: Thu Aug 14, 2014 7:59 pm
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...

Re: GRUB2 Higher-Half 64 Bit

Posted: Fri Aug 15, 2014 6:21 pm
by dschatz
Post linker script and assembly, also grub version

Re: GRUB2 Higher-Half 64 Bit

Posted: Fri Oct 10, 2014 2:11 pm
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

Re: GRUB2 Higher-Half 64 Bit

Posted: Fri Oct 10, 2014 2:31 pm
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.

Re: GRUB2 Higher-Half 64 Bit

Posted: Fri Oct 10, 2014 2:54 pm
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.