Page 1 of 1

qemu multiboot issue

Posted: Tue Sep 20, 2011 9:17 am
by Dumah
While still messing about trying to fix the issue in my post from the other day (http://forum.osdev.org/viewtopic.php?f=1&t=24163) I noticed that global and static variables in my C code were not being initialised to zero.

I am testing on qemu using its '-kernel' command line. As far as I understand it, loading a protected mode kernel with a valid multiboot header should work fine, also when loading the kernel, qemu should zero out the memory where the bss section is loaded. Unfortunately, this last part doesn't seem to be happening.

If I load a grub disk, copy my kernel into it and then run it through bochs, it seems the memory is zeroed - is this a bug with qemu or a bug in my code?

Here's my initialisation code (more or less exactly like bran's kernel tut)

Code: Select all

[BITS 32]
global start
start:
	mov esp, _sys_stack 
	jmp stublet

ALIGN 4
mboot:
	MULTIBOOT_PAGE_ALIGN	equ 1<<0
	MULTIBOOT_MEMORY_INFO	equ 1<<1
	MULTIBOOT_AOUT_KLUDGE	equ 1<<16
	MULTIBOOT_HEADER_MAGIC	equ 0x1BADB002
	MULTIBOOT_HEADER_FLAGS	equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE
	MULTIBOOT_CHECKSUM	equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS)
	EXTERN code, bss, end

	dd MULTIBOOT_HEADER_MAGIC
	dd MULTIBOOT_HEADER_FLAGS
	dd MULTIBOOT_CHECKSUM
    
	dd mboot
	dd code
	dd bss
	dd end
	dd start

stublet:

extern kmain
	call kmain
...
Here's my link script

Code: Select all

OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
phys = 0x00100000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(4096);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(COMMON)
    *(.bss)
    . = ALIGN(4096);
  }
  end = .;
}
Here's part of my kmain code that shows the error

Code: Select all

int ticks;

void kmain()
{
...
        char buff[0x100];
	itoa(ticks, buff);
	puts("ticks - ");
	puts(buff);
	puts("\n");
}
On bochs with grub it prints "ticks - 0". On qemu it prints a garbage number.

Any ideas?

Re: qemu multiboot issue

Posted: Wed Sep 21, 2011 2:22 am
by AJ
Hi,
Dumah wrote:On bochs with grub it prints "ticks - 0". On qemu it prints a garbage number. Any ideas?
Yes:

Code: Select all

int ticks = 0;
You cannot assume that any variables (global, static or local) will be initialised to zero. Local variables are assigned on the stack, which contains old data from the stack and globals are contained either in the heap or in your .data section. When a PC boots, it does not clear the memory. C does not implicitly zero variables for you.

Cheers,
Adam

[Edit: In other words, qemu's behaviour in this case is more like that of real hardware. IIRC, there was a way to get bochs to fill the RAM with junk for testing purposes (or perhaps you could do this yourself in the boot loader when a DEBUG flag is set?)]

Re: qemu multiboot issue

Posted: Wed Sep 21, 2011 2:39 am
by gerryg400
AJ wrote:You cannot assume that any variables (global, static or local) will be initialised to zero. Local variables are assigned on the stack, which contains old data from the stack and globals are contained either in the heap or in your .data section. When a PC boots, it does not clear the memory. C does not implicitly zero variables for you.
Global and static variables are initialised to zero. Local variables are not. This is C. The loader and the c startup code co-operate to make sure that happens.

If an environment doesn't zero initialised global and static variables then either the loader or the c startup code is broken or they are mismatched. Furthermore compilers will in most cases generate exactly the same binary image for code like this in global scope.

Code: Select all

int ticks;
and this

Code: Select all

int ticks = 0;
So it possibly won't help.

Re: qemu multiboot issue

Posted: Wed Sep 21, 2011 3:21 am
by Dumah
gerryg400 wrote:Global and static variables are initialised to zero. Local variables are not. This is C. The loader and the c startup code co-operate to make sure that happens.

If an environment doesn't zero initialised global and static variables then either the loader or the c startup code is broken or they are mismatched. Furthermore compilers will in most cases generate exactly the same binary image for code like this in global scope.

Code: Select all

int ticks;
and this

Code: Select all

int ticks = 0;
So it possibly won't help.
Indeed. If I initialize it to zero it still comes up with garbage as I understand that any decent compiler will assume that the memory will be zeroed and will therefore ignore the assignment for an integer variable.

Following on from my problem a few days ago I built a cross compiler using the tutorial on this site. Its using the most recent GCC and the build went as planned.
nasm "-f elf" -g -o kernel/kernel_init.o kernel/kernel_init.asm
i586-elf-gcc -o kernel/kernel_irq.o -c --std=c99 --freestanding -Wall -fno-builtin -g -Ikernel/include kernel/kernel_irq.c
i586-elf-gcc -o kernel/kernel_isr.o -c --std=c99 --freestanding -Wall -fno-builtin -g -Ikernel/include kernel/kernel_isr.c
i586-elf-gcc -o kernel/kernel_main.o -c --std=c99 --freestanding -Wall -fno-builtin -g -Ikernel/include kernel/kernel_main.c
i586-elf-gcc -o kernel/kernel_screen.o -c --std=c99 --freestanding -Wall -fno-builtin -g -Ikernel/include kernel/kernel_screen.c
i586-elf-gcc -o kernel/kernel_setup.o -c --std=c99 --freestanding -Wall -fno-builtin -g -Ikernel/include kernel/kernel_setup.c
i586-elf-gcc -o kernel/kernel_util.o -c --std=c99 --freestanding -Wall -fno-builtin -g -Ikernel/include kernel/kernel_util.c
nasm "-f elf" -g -o kernel/kernel_memory.o kernel/kernel_memory.asm
i586-elf-ld -T kernel/link.ld -o kernel/kernel.bin kernel/kernel_init.o kernel/kernel_irq.o kernel/kernel_isr.o kernel/kernel_main.o kernel/kernel_screen.o kernel/kernel_setup.o kernel/kernel_util.o kernel/kernel_memory.o
Here's the build output. Anything there that looks amiss? Any command options I should be adding?

Re: qemu multiboot issue

Posted: Wed Sep 21, 2011 3:39 am
by Dumah
Weird.

I rewrote my linker script using the docs I found on the web and now it's working. The variable is now zero!

Here's my revised script

Code: Select all

OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
phys = 0x00100000;
SECTIONS
{
	.text ALIGN(0x1000) : AT(phys)
	{
		code = .; *(.text) *(.rodata)
	}
  	.data ALIGN(0x1000) : AT(phys + (data - code))
	{
		data = .; *(.data)
	}
  	.bss ALIGN(0x1000) : AT(phys + (bss - code))
  	{
		bss = .; *(.bss) *(COMMON)
  	}
  	end = .;
}