I am trying to write a very basic kernel for i386 32-bit. I have been following JamesM's kernel tutorials. My kernel code itself currently does very little - where I am struggling is trying to get grub to correctly load the higher-half format I've chosen to work with.
The advice for doing that is described in this answer and I'm working roughly with the higher half bare bones. My test environment is bochs, with a grub floppy (0.97/legacy).
To give you an idea of where I'm up to, I have a very simple do-almost-nothing "main" routine:
[section .text]
align 4
; setting up entry point for linker
start equ (start_vma - 0xBFF00000)
; entry point
start_vma:
push ebx
mov eax, 0xCCCCCCCC
hlt
This technique gives me:
bjdump -x kernel | grep "start"
start address 0x00100000
c0000000 g .text 00000000 start_vma
00100000 g .text 00000000 start
Then what I have done is to use the linker script to set the LMA (physical address load points) to 1MB, but the VMAs to 3GB, like so:
OUTPUT_FORMAT(elf32-i386)
ENTRY(start)
KERNEL_MBOOT = 0x400;
KERNEL_VMA = 0xC0000000;
KERNEL_LMA_OFFSET = 0xBFF00000;
PHDRS
{
headers PT_PHDR PHDRS ;
mboot PT_LOAD FILEHDR ;
text PT_LOAD FILEHDR ;
data PT_LOAD ;
}
SECTIONS
{
. = KERNEL_MBOOT;
.mboot : AT(KERNEL_VMA - KERNEL_LMA_OFFSET)
{
*(.mboot)
} : mboot
. = KERNEL_VMA;
.text : AT(ADDR(.text)+ADDR(.mboot) - KERNEL_LMA_OFFSET)
{
code = .; _code = .; __code = .;*/
*(.text)
*(.rodata*)
} : text
.data ALIGN (0x1000) : AT(ADDR(.data) - KERNEL_LMA_OFFSET)
{
data = .; _data = .; __data = .;
*(.data)
*(.rodata)
} : data
.bss : AT(ADDR(.bss) - KERNEL_LMA_OFFSET)
{
bss = .; _bss = .; __bss = .;
*(.bss)
*(COMMON)
ebss = .;
} : data
end = .; _end = .; __end = .;
}
Or at least so I believe. Explanation. Certainly, this is what I have in my object:
$ objdump -h kernel.bin
file format elf32-i386
Sections:
Idx Name Size VMA LMA File off Algn
0 .mboot 0000000c 00000400 00100000 00000400 2**2
CONTENTS, ALLOC, LOAD, READONLY, DATA
1 .text 0000002e c0000000 00100400 00001000 2**4
CONTENTS, ALLOC, LOAD, READONLY, CODE
2 .data 00000001 c0001000 00101000 00002000 2**12
CONTENTS, ALLOC, LOAD, DATA
3 .bss 00004000 c0001020 00101020 00002001 2**5
ALLOC
The .mboot
section contains just the multiboot header. Indeed, running mbchk gives:
kernel: The Multiboot header is found at the offset 1024.
kernel: Page alignment is turned on.
kernel: Memory information is turned on.
kernel: Address fields is turned off.
kernel: All checks passed.
So all in all, this looks like a valid, should be booting elf kernel that does absolutely nothing.
However, it actually isn't booting. Instead, grub complains like so:
error 28: selected item cannot fit into memory
I am building with gcc 4.7.2 on x64 fedora, with:
CFLAGS=-nostdlib -fno-builtin -fno-stack-protector -ffreestanding -m32
LDFLAGS=-melf_i386 -Tlink.ld
Where link.ld
is the script I've included above.
My question is, what am I doing wrong in the above to make grub believe that the kernel can fit into memory? I have tried:
- Altering the VMA_OFFSET fields to make the VMA match the LMA i.e. load everything at 1MB physical and virtual makes no difference, i.e. I get the same error.
- Bringing the LMA to below 1MB. Causes grub error 7: cannot load below 1MB, as expected.
- Binge drinking tea and coffee.
None of these things worked. I have the feeling I am missing something quite obvious, but can't work out what it is.
Update: looking at the grub multiboot elf line, here's what I see:
[Multiboot-elf, <0xffc00:0x40c:0x0>
Crucially, I believe I am supposed to see is something like the line featured in this question, namely it should have an entry=
part!
Anyway, I looked at providing an init region:
[section .init]
; setting up entry point for linker
; entry point
start:
push ebx
mov eax, 0xCCCCCCCC
; jmp later
hlt
Which I linked like so:
.init : AT(ADDR(.mboot) + (KERNEL_VMA - KERNEL_LMA_OFFSET))
{
*(.init)
} : init
To give:
Idx Name Size VMA LMA File off Algn
1 .init 0000000c 00100000 00100400 00001000 2**0
Which has a VMA/LMA of around 1M, so this should load... but I'm still getting complaints about the selected item not fitting into memory.