Page 1 of 1

[GRUB] Error 7: Loading below 1MB is not supported

Posted: Fri Mar 07, 2008 11:40 am
by Paw
Dear board members,

after four hours of debugging attempts, I gave up and decided to register here in order to ask you for help for my current "pet OS" problem.

My Kernel's bootloader is based on JamesM's bootloader tutorial, using GRUB. The Kernel itself is written in C.

After adding a few minor functions to the kernel code, the Kernel wouldn't be recognized by GRUB anymore.
Due to the increasing code size, the multiboot loader header was shifted out of reach for GRUB. So I modified the boot loader by adding a section called .mboot:

Code: Select all

MBOOT_PAGE_ALIGN    equ 1<<0        ; Load kernel and modules on a page boundary
MBOOT_MEM_INFO      equ 1<<1        ; Provide your kernel with memory info
MBOOT_HEADER_MAGIC  equ 0x1BADB002  ; Multiboot Magic value
; NOTE: We do not use MBOOT_AOUT_KLUDGE. It means that GRUB does not
; pass us a symbol table.
MBOOT_HEADER_FLAGS  equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO
MBOOT_CHECKSUM      equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)

[BITS 32]                       ; All instructions should be 32-bit.

[GLOBAL mboot]                  ; Make 'mboot' accessible from C.
[EXTERN code]                   ; Start of the '.text' section.
[EXTERN bss]                    ; Start of the .bss section.
[EXTERN end]                    ; End of the last loadable section.

SECTION .mboot ALIGN 4
mboot:
  dd  MBOOT_HEADER_MAGIC        ; GRUB will search for this value on each
                                ; 4-byte boundary in your kernel file
  dd  MBOOT_HEADER_FLAGS        ; How GRUB should load your file / settings
  dd  MBOOT_CHECKSUM            ; To ensure that the above values are correct
   
  dd  mboot                     ; Location of this descriptor
  dd  code                      ; Start of kernel '.text' (code) section.
  dd  bss                       ; End of kernel '.data' section.
  dd  end                       ; End of kernel.
  dd  start                     ; Kernel entry point (initial EIP).

[GLOBAL start]                  ; Kernel entry point.
[EXTERN kmain]                  ; This is the entry point of our C code

SECTION .text ALIGN 4096
start:
  push    ebx                   ; Load multiboot header location

  ; Execute the kernel:
  cli                         ; Disable interrupts.
  call kmain                  ; call our main() function.
  jmp $                       ; Enter an infinite loop, to stop the processor
                              ; executing whatever rubbish is in the memory
                              ; after our kernel! 
And I modified my linker script link.ld accordingly, so the header information is reachable again, for GRUB.

Code: Select all

ENTRY(start)
phys = 0x00100000;

SECTIONS {
  start = .;

  .text ALIGN(4096) : AT(phys) {
    code = .;
    *(.mboot)
    *(.text)
    *(.rodata)
  }

  .data ALIGN(4096) : {
    data = .;
    *(.data)
  }

  .bss ALIGN(4096) : {
    bss = .;
    *(.bss)
  }

  end = .;
}
After these modifications, however, I get following GRUB error message:

Code: Select all

Error 7: Loading below 1MB is not supported
I'm pretty much stuck now, since I cannot see which section is about to be loaded below 1MB.

Here's the objdump output:

Code: Select all

kernel.bin:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00001320  00000000  00100000  00001000  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         0000000c  00002000  00102000  00003000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .comment      00000174  00000000  00000000  0000300c  2**0
                  CONTENTS, READONLY
I'd appreciate a helping hand here, since solutions to similar problems on this board unfortunately don't seem to apply to my situation :?

Many thanks in advance!

Paw

Posted: Fri Mar 07, 2008 12:36 pm
by jzgriffin
Try this:

Code: Select all

MBOOT_PAGE_ALIGN    equ 1<<0        ; Load kernel and modules on a page boundary
MBOOT_MEM_INFO      equ 1<<1        ; Provide your kernel with memory info
MBOOT_HEADER_MAGIC  equ 0x1BADB002  ; Multiboot Magic value
; NOTE: We do not use MBOOT_AOUT_KLUDGE. It means that GRUB does not
; pass us a symbol table.
MBOOT_HEADER_FLAGS  equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO
MBOOT_CHECKSUM      equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)

[BITS 32]                       ; All instructions should be 32-bit.

[EXTERN code]                   ; Start of the '.text' section.
[EXTERN bss]                    ; Start of the .bss section.
[EXTERN end]                    ; End of the last loadable section.

[GLOBAL start]
start:
    jmp start2

align 4
mboot:
  dd  MBOOT_HEADER_MAGIC        ; GRUB will search for this value on each
                                ; 4-byte boundary in your kernel file
  dd  MBOOT_HEADER_FLAGS        ; How GRUB should load your file / settings
  dd  MBOOT_CHECKSUM            ; To ensure that the above values are correct
   
  dd  mboot                     ; Location of this descriptor
  dd  code                      ; Start of kernel '.text' (code) section.
  dd  bss                       ; End of kernel '.data' section.
  dd  end                       ; End of kernel.
  dd  start                     ; Kernel entry point (initial EIP).

[EXTERN kmain]                  ; This is the entry point of our C code
start2:
  push    ebx                   ; Load multiboot header location

  ; Execute the kernel:
  cli                         ; Disable interrupts.
  call kmain                  ; call our main() function.
  jmp $                       ; Enter an infinite loop, to stop the processor
                              ; executing whatever rubbish is in the memory
                              ; after our kernel! 
You shouldn't need a whole section for the multiboot header.

Edit:

Code: Select all

ENTRY(start)
phys = 0x00100000;

SECTIONS {
  start = .;

  .text 0x00100000 : {
    code = .;
    *(.text)
    . = ALIGN(4096);
  }

  .data : {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }

  .bss : {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }

  end = .;
}

Posted: Fri Mar 07, 2008 12:48 pm
by Paw
Thanks Jeremiah, for the suggestion. I tried your code, but unfortunately, the former GRUB problem re-appears:

Code: Select all

Error 13: Invalid or unsupported executable format
And mbcheck returns following message:

Code: Select all

kernel.bin: No Multiboot header.
I think I'm going to give some more context. Here is my Makefile for building the kernel.bin image:

Code: Select all

CSOURCES := $(shell find . -name "*.c")
ASOURCES := $(shell find . -name "*.s")
SOURCES  := $(CSOURCES) $(ASOURCES)
OBJFILES := $(patsubst %.c,%.o,$(CSOURCES)) $(patsubst %.s,%.o,$(ASOURCES))
DEPFILES := $(patsubst %.c,%.d,$(SRCFILES))

CC       := gcc
AS       := nasm
CFLAGS   := -Wall -Werror -nostdlib -nostartfiles -nodefaultlibs -nostdinc -fno-builtin -fno-stack-protector
LDFLAGS  := -Tlink.ld
ASFLAGS  := -felf

all: kernel

kernel: $(OBJFILES)
	@ld $(LDFLAGS) -o kernel.bin $(OBJFILES)

%.o: %.c Makefile
	@$(CC) $(CFLAGS) -c $< -o $@

%.o: %.s Makefile
	@$(AS) $(ASFLAGS) -o $@ $<

clean:
	-@for file in $(OBJFILES) $(DEPFILES) kernel.bin; do if [ -f $$file ]; then rm $$file; fi; \
done

Posted: Fri Mar 07, 2008 12:53 pm
by jzgriffin

Code: Select all

OBJFILES := $(patsubst %.s,%.o,$(ASOURCES)) $(patsubst %.c,%.o,$(CSOURCES))
You need to link the .o file containing start and mboot before your C objects.

Posted: Fri Mar 07, 2008 1:03 pm
by Paw
Jeremiah Griffin wrote:

Code: Select all

OBJFILES := $(patsubst %.s,%.o,$(ASOURCES)) $(patsubst %.c,%.o,$(CSOURCES))
You need to link the .o file containing start and mboot before your C objects.
Ouch.... hehe, yeah that sounds reasonable. Unfortunately it still does not work. It's the "below 1MB error" again. Something appears to be pretty screwed here :-/

I'll dive a little deeper and have a look at the GRUB multiboot header specification.

Posted: Fri Mar 07, 2008 1:17 pm
by jzgriffin
What does objdump say, now?

Also, here's my Startup.asm and System.ld files (C++ crap removed):

Code: Select all

OUTPUT_FORMAT("elf32-i386")
ENTRY(Startup)

SECTIONS
{
	.text 0x0100000 :
	{
		code = .;
		*(.text)
		. = ALIGN(4096);
	}
	.data :
	{
		data = .;
		*(.data)
		. = ALIGN(4096);
	}
	.bss :
	{
		bss = .;
		*(.bss)
		. = ALIGN(4096);
	}
	
	end = .;
}

Code: Select all

	bits	32
	global	Startup

Startup:
	mov		esp, Stack
	jmp		Startup2
	
	align	4
Multiboot:
	MULTIBOOT_PAGE_ALIGN	equ 1<<0
	MULTIBOOT_MEMORY_INFO	equ 1<<1
	MULTIBOOT_HEADER_MAGIC	equ 0x1BADB002
	MULTIBOOT_HEADER_FLAGS	equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO
	CHECKSUM				equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
	extern	code, bss, end
	dd		MULTIBOOT_HEADER_MAGIC
	dd		MULTIBOOT_HEADER_FLAGS
	dd		CHECKSUM
	dd		Multiboot
	dd		code
	dd		bss
	dd		end
	dd		Startup

Startup2:
	extern	Setup
	cli
	call	Setup
	cli
	hlt
	
	section	.bss
	resb	8192
Stack:
Maybe that will help you.

Posted: Fri Mar 07, 2008 1:34 pm
by JamesM
Hi,

If you look at your objdump output you'll see that the VMA != LMA, as in the virtual address the section is to be loaded starts at zero.

I'm not sure what's causing this, and it's different to my own kernel (which is what caused me to flag up the problem in the first place) - but it's got to be something in the link stage.

The only difference between my link script and yours is I don't use the AT() syntax, mine is pretty much identical to Jeremiah's. You should try that, and see if it resolves the problem.

Cheers,

James

Posted: Fri Mar 07, 2008 1:37 pm
by Paw
Thanks for your patience. I took over your boot loader and linker script and modified it to my needs. The "under 1MB problem" still stays, though.

objdump tells:

Code: Select all

kernel.bin:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00002000  00100000  00100000  00001000  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00001000  00102000  00102000  00003000  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          00002000  00103000  00103000  00004000  2**2
                  ALLOC
  3 .comment      00000174  00000000  00000000  00004000  2**0
                  CONTENTS, READONLY
I suspect that the problem is somewhere else. The strange thing is, that everything worked fine yesterday. I just added a C code stub for a stack datastructure, which doesn't contain anything. Since then the kernel is broken...

EDIT:

@JamesM: Thanks for the hint. Very strange, that my latest objdump gives identical VMA/LMA values... Ah... what a bad start in OS deving :-(

Posted: Fri Mar 07, 2008 1:49 pm
by jzgriffin
Objdump of my kernel for comparison:

Code: Select all

System.sys:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
  0 .text         00002000  00100000  00100000  00001000  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .rodata       00000126  00102000  00102000  00003000  2**2
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
  2 .data         00000ed8  00102128  00102128  00003128  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  3 .bss          00003000  00103000  00103000  00004000  2**5
                  ALLOC
  4 .comment      0000010c  00000000  00000000  00004000  2**0
                  CONTENTS, READONLY
Our .text sections are the same, and mine boots fine. Where did you get your GRUB?

Posted: Fri Mar 07, 2008 2:07 pm
by Paw
Jeremiah Griffin wrote:Where did you get your GRUB?
I'm using the "floppy.img" file from James' tutorial, which has GRUB preinstalled. Unfortunately I don't know which version it is.

Posted: Fri Mar 07, 2008 2:20 pm
by jzgriffin
Would it be possible for you to post all of the code? You know, so that we could get a better look at it, run it through our own compilers, etc. It's fine if you don't want to. :-)

Posted: Fri Mar 07, 2008 2:46 pm
by Paw
Jeremiah Griffin wrote:Would it be possible for you to post all of the code? You know, so that we could get a better look at it, run it through our own compilers, etc. It's fine if you don't want to. :-)
This must be one of the most helpful forums on the Net :-)
I added a tar package as an attachement to this post.

Posted: Fri Mar 07, 2008 3:08 pm
by jzgriffin
Okay, cool. I haven't fixed it yet but I'll keep working on it. Spotted a problem with your linker script, though. It should be:

Code: Select all

OUTPUT_FORMAT("elf32-i386") 
ENTRY(Startup)

SECTIONS {
  .text 0x0100000 : {
    code = .;
    *(.text)
    . = ALIGN(4096);
  }

  .data : {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }

  .bss : {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }

  end = .;
}

Posted: Fri Mar 07, 2008 3:19 pm
by Paw
Jeremiah Griffin wrote:Okay, cool. I haven't fixed it yet but I'll keep working on it. Spotted a problem with your linker script, though. It should be:

Code: Select all

OUTPUT_FORMAT("elf32-i386") 
ENTRY(Startup)

SECTIONS {
  .text 0x0100000 : {
    code = .;
    *(.text)
    . = ALIGN(4096);
  }

  .data : {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }

  .bss : {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }

  end = .;
}

It works again! Pew... what a relieve. Thank you very much for your help :-)

Posted: Fri Mar 07, 2008 3:24 pm
by jzgriffin
You're welcome. It seemed like the right fix, but it wouldn't boot for me. Maybe I forgot to ./update_image.sh. :-P