2

I'm creating my own OS just for fun.

My kernel is a 64-bits ELF binary with the multiboot header. I use grub-mkrescue to build an .iso file to boot on my kernel and I test it with qemu + tianocore (UEFI).

My kernel is composed of a simple main function which print pixels on the screen. But my global variables, saved in the .data segment, does not seem to be loaded. Indeed, if I use a global variable pixels to set the number of pixels to draw no pixel is printed (but if pixels variable is local to the main function then the pixels are drawn).

The loader.s (multiboot header + call kernel start function) :

section .multiboot               
align 4
    dd 0x1BADB002               ; magic
    dd 0x6                      ; flags
    dd - (0x1BADB002 + 0x6)     ; checksum
    dd 0                        ; header_addr
    dd 0                        ; load_addr
    dd 0                        ; load_end_addr
    dd 0                        ; bss_end_addr
    dd 0                        ; entry_addr
    dd 0                        ; mode_type
    dd 1024                     ; width
    dd 768                      ; height
    dd 32                       ; depth

section .text
global _start
extern kstart                    ; defined in the C file

_start:
        cli                      ; block interrupts
        mov rsp, stack_space     ; set stack pointer
    
        call kstart              ; call kernel start function
        hlt                      ; halt the CPU

section .bss
resb 8192                        ; 8KB for stack
stack_space:

The kernel C code kmain.c with start function :

unsigned int pixels = 10;

void put_pixel(unsigned int i)
{
    unsigned int *graphics_memory = (unsigned int *) 0xA0000;
    graphics_memory[i] = 0xffffffff;
}

int kstart(unsigned int addr)
{
    unsigned int p;

    for (p = 0; p < pixels; p++)
        put_pixel(p);

    return 0;
}

The linker script link.ld :

OUTPUT_FORMAT(elf64-x86-64)
ENTRY(_start)

SECTIONS {
    . = 1M;     
    
    .text ALIGN (0x1000) :      /* align at 4 KB */
    {
        *(.multiboot)
        *(.text)                /* all text sections from all files */
    }

    .rodata ALIGN (0x1000) :    /* align at 4 KB */
    {
        *(.rodata*)             /* all read-only data sections from all files */
    }
    
    .data ALIGN (0x1000) :      /* align at 4 KB */
    {
        *(.data)                /* all data sections from all files */
    }

    .bss ALIGN (0x1000) :       /* align at 4 KB */
    {
        *(COMMON)               /* all COMMON sections from all files */
        *(.bss)                 /* all bss sections from all files */
    }
}

From what I understand, the bootloader GRUB will read the ELF header and load the segments. I'm right ? Did I miss something ?

Michael Petch
  • 46,082
  • 8
  • 107
  • 198
JackPots
  • 43
  • 1
  • 8
  • 3
    Grub Multiboot doesn't put the processor in long mode (64-bit mode). Multiboot only guarantees your 32-bit protected mode with the A20 line enabled and that is it. 64-bit code will not behave properly in 32-bit protected mode. Your code likely won't work until you add code to put the processor in long mode before calling the kernel. – Michael Petch Oct 12 '22 at 19:35
  • 3
    Thank for your leads. I tried this [tuto](http://ringzeroandlower.com/2017/08/08/x86-64-kernel-boot.html) (Grub with x86 64-bit long mode) and my data segment is correctly loaded ! I did not know about this long mode stuff, I will explore that to adapt my current code. – JackPots Oct 12 '22 at 20:49

0 Answers0