Booting non-ELF kernel with GRUB tutorial
Page 1 of 1

Author:  gedd [ Tue Dec 01, 2009 11:08 am ]
Post subject:  Booting non-ELF kernel with GRUB tutorial

Here are 2 basic tutorials to make GRUB booting non-ELF kernel, one for flat binary and one for PE format kernel.
Both have been tested on windows


- A correct floppy with GRUB installed to match this menu.cfg
title   DNA Workstation
root    (fd0)
kernel  /init.bin

- nasm
- Visual C++ [Express edition is enough and free]

Flat binary kernel

the code init.asm

         [map all init.map]         ;Nasm directive to produce map file
         bits 32                  ;necessary to avoid Nasm to produce 16 bits  code
MULTIBOOT_HEADER_MAGIC   equ   0x1BADB002   ;magic number, GRUB search for it in the first 8k
                              ;of the specified file in GRUB menu
MULTIBOOT_HEADER_FLAGS   equ   0x00010000   ;FLAGS[16] say to GRUB we are not
                              ;an ELF executable and the fields
                              ;header adress, load adress, load end adress;
                              ;bss end adress and entry adress will be available
                              ;in Multiboot header

LOADBASE            equ 0x00100000   ;Must be >= 1Mo

STACK_SIZE              equ   0x4000

       jmp     multiboot_entry         ;if you want use you own bootloader               

       align  4                     ;Multiboot header must be 32
                                 ;bits aligned to avoid error 13
       dd   MULTIBOOT_HEADER_MAGIC      ;magic number
       dd   MULTIBOOT_HEADER_FLAGS      ;flags
       dd   CHECKSUM                  ;checksum
       dd   LOADBASE + multiboot_header   ;header adress
       dd   LOADBASE                  ;load adress
       dd   00                     ;load end adress : not necessary
       dd   00                     ;bss end adress : not necessary
       dd   LOADBASE + multiboot_entry   ;entry adress
      mov    esp, stack + STACK_SIZE      ;Setup the stack
      push   0                     ;Reset EFLAGS
      push   ebx                     ;Push magic number and
      push   eax                     ;multiboot info adress
                                 ;which are loaded in registers
                                 ;eax and ebx before jump to
                                 ;entry adress
                                 ;[LOADBASE + multiboot_entry]
      ;call   EXT_C(main)               ; !! commented
                                 ;main (unsigned long magic, unsigned long addr)
                                 ;your kernel entry point
       mov   edi, 0xB8000            ;Msg to check the boot was OK
       mov   esi, hello
       add   esi, LOADBASE            ;hello is just an offset
       mov   byte al, [esi]
       cmp   al, '\0'
       je   loop
       mov   ah, 0xa0                                     
       mov   word [edi],   ax         
       add   edi, 2
       inc   esi
       jmp   msg
       loop:   hlt                        ;Halt processor
             jmp     loop
   db   "Hello world from GRUB and flat binary kernel !\0"   
   align 4
   times (128) db 0x00                     ;foo data
   align 4
   times (STACK_SIZE) db 00

-Assemble with nasm : nasm -f bin -o init.bin init.asm
-copy init.bin at the floppy root

PE Kernel

This is a bit more complicated

First you must setup a Visual C++ project named init like as describe in the famous BrokenThorn tutorials Setup Visual c++

Some modificatione are required
in code generation set Enable Function level linking to yes (/Gy)
in command line set /ALIGN=1024
and add in Optimisation-> Functions order : @order.txt (@ is to avoid LNK warning)

Add a txt file order.txt (without @), leave blank

Add init .h file

/*   _emit is DB equivalent but not DD equivalent exist
   so we define it ourself */
#define dd(x)                            \
        __asm _emit     (x)       & 0xff \
        __asm _emit     (x) >> 8  & 0xff \
        __asm _emit     (x) >> 16 & 0xff \
        __asm _emit     (x) >> 24 & 0xff

#define KERNEL_STACK         0x00104000

/*  This is the one of most important thing to be able to load a PE kernel
   with GRUB. Because PE header are in the begining of the file, code section
   will be shifted. The value used to shift the code section is the linker
   align option /ALIGN:value. Note the header size sum is larger than 512,
   so ALIGN value must be greater */
#define   ALIGN               0x400

/*   Must be >= 1Mo for GRUB
   Base adress from advanced libker option
#define LOADBASE            0x100000


#define MULTIBOOT_HEADER_MAGIC         0x1BADB002
#define MULTIBOOT_HEADER_FLAGS         0x00010003
#define STACK_SIZE              0x4000   

void main(unsigned long, unsigned long);

Add init.cpp file
// init.cpp : définit le point d'entrée pour l'application console.

#include "init.h"

__declspec(naked) void multiboot_entry(void)
      align 4

                dd(MULTIBOOT_HEADER_MAGIC)      ; magic number
                dd(MULTIBOOT_HEADER_FLAGS)      ; flags
                dd(CHECKSUM)               ; checksum
                dd(HEADER_ADRESS)            ; header address
                dd(LOADBASE)               ; load address
            dd(00)                     ; load end address : not used
            dd(00)                     ; bss end addr : not used
            dd(HEADER_ADRESS + 0x20)      ; entry_addr : equ kernel entry      
                                    ; 0x20 is the size of multiboot heeader
                mov     esp,     KERNEL_STACK   ;Setup the stack

                push    0                  ;Reset EFLAGS

                push    ebx                  ;Push multiboot info adress
                push    eax                  ;and magic number 
                                    ;which are loaded in registers
                                    ;eax and ebx before jump to
                                    ;entry adress
                                    ;[HEADER_ADRESS + 0x20]
                call    main               ;kernel entry
            jmp halt                  ; halt processor


void main(unsigned long magic, unsigned long addr)
   char *string = "Hello World from GRUB and PE kernel !", *ch;
    unsigned short *vidmem = (unsigned short *) 0xB8000;
    int i;
        for(ch = string, i = 0; *ch; ch++, i++)
                vidmem[i] = (unsigned char) *ch | 0xA000;


Take a look at your map file, it should be like this :

Timestamp is 4b1549e9 (Tue Dec 01 17:52:57 2009)

Preferred load address is 00100000

Start         Length     Name                   Class
0001:00000000 000000a5H .text                   CODE
0002:00000000 00000026H .rdata                  DATA

  Address         Publics by Value              Rva+Base       Lib:Object

0000:00000000       ___safe_se_handler_count   00000000     <absolute>
0000:00000000       ___safe_se_handler_table   00000000     <absolute>
0001:00000000       ?multiboot_entry@@YAXXZ    00100400 f   init.obj
0001:00000040       _main                      00100440 f   init.obj
0002:00000000       ??_C@_0CG@IINAHCGJ@Hello?5World?5from?5GRUB?5and?5PE?5ker@ 00100800     init.obj

entry point at        0000:00000000

Static symbols

Put this in your order.txt ?multiboot_entry@@YAXXZ
This ensure that when your kernel will growing, the multiboot_entry function will be at the beginning of file

- build
- copy the output file in the floppy root
- test

This is not a perfect tutorial but it is quite good to begin

Please report me any error, suggestion and your test result

Author:  madeofstaples [ Tue Dec 01, 2009 12:04 pm ]
Post subject:  Re: Booting non-ELF kernel with GRUB tutorial by a prick

Interesting, but I was a little disappointed that none of your comments or your tutorial in general made you sound like a prick, as promised by the thread title.

It looks like a useful tutorial, I admit I skimmed it a bit because I'm not currently working on anything related, but I may save a copy for reference later.

The only thing I did notice is that you should use the hlt instruction between the "halt" label and "jmp halt" command in init.cpp; perhaps disabling maskable interrupts with cli before the "halt" label.

Author:  gedd [ Tue Dec 01, 2009 12:36 pm ]
Post subject:  Re: Booting non-ELF kernel with GRUB tutorial by a prick

The prick was a reference from another thread wich have been locked.

Few year ago hlt instruction doesn't work fine in some virtualizer, it's an hold habit tu use infinite loop.
The forgoten CLI is clearly a mistake

Author:  neon [ Tue Dec 01, 2009 1:02 pm ]
Post subject:  Re: Booting non-ELF kernel with GRUB tutorial by a prick

Id remove that "reference" from the thread title. Its nice that you are sharing self written tutorials, I would keep it at that :)

Author:  Love4Boobies [ Mon Jan 11, 2010 12:07 pm ]
Post subject:  Re: Booting non-ELF kernel with GRUB tutorial

Can you really be far even as decided half as much to use go wish for that?

Author:  gedd [ Tue Jan 12, 2010 2:37 am ]
Post subject:  Re: Booting non-ELF kernel with GRUB tutorial

Sorry for my question but i'm not understand your sentence
I 'm not english, can you rewrite ?

Page 1 of 1 All times are UTC - 6 hours
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group