Hi,
I am new to OS development, for the past few days I have been trying to develop a very simple bootloader that can jump to my kernel entrypoint.
I have several details in the repository, including the desired memory map: https://github.com/fx310ferreira/operat ... bootloader
Right now I am loading the kernel on the address 0x10000, the kernel has a ELF header so when linking I am using the address 0x11000 for the ".text" segment.
Before I was using normal gcc and not i686-elf-gcc. Everything was working, using GCC I verified that on the address 0x11000 my _start function was loaded. When I changed to the cross-compiler it stop working.
Does someone have an idea why? Did I misunderstand something related to ELF headers?
Thank you in advance.
Code is not correct on Kernel entrypoint - custom bootloader
-
- Posts: 2
- Joined: Sun Jan 19, 2025 8:18 am
-
- Member
- Posts: 5623
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Code is not correct on Kernel entrypoint - custom bootloader
No you aren't.batatonana wrote: ↑Sun Jan 19, 2025 8:58 amRight now I am loading the kernel on the address 0x10000,
No it doesn't.
It's hard to help you when you show us the wrong code.
Did you try using tools like readelf or objdump or just a plain hex editor to see if your binary is laid out the way you expect?
-
- Posts: 2
- Joined: Sun Jan 19, 2025 8:18 am
Re: Code is not correct on Kernel entrypoint - custom bootloader
I am so sorry, you are completely right, it seems I forgot to push the correct version.
I have pushed the correct, one.
The on the version that you have seen everything was working fine I was loading a plain .asm file instead of the compiled C version, I have used both readelf and objdump, I will try the plain hex editor to see if there is a difference between the compiled version with normal GCC and cross-compiler (with both objdump and readleaf it seems to be the exact same file).
Other thing I have question about is that most of the implementations of the bootloader and kernel I have is to use a "boot.asm" file to call an external "kernel.c" function. Is this a better practice than calling directly the C function?
I have pushed the correct, one.
The on the version that you have seen everything was working fine I was loading a plain .asm file instead of the compiled C version, I have used both readelf and objdump, I will try the plain hex editor to see if there is a difference between the compiled version with normal GCC and cross-compiler (with both objdump and readleaf it seems to be the exact same file).
Other thing I have question about is that most of the implementations of the bootloader and kernel I have is to use a "boot.asm" file to call an external "kernel.c" function. Is this a better practice than calling directly the C function?
-
- Member
- Posts: 5623
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Code is not correct on Kernel entrypoint - custom bootloader
Does your entire kernel get copied to your disk image?
Most implementations have that because they won't work correctly without it. If your bootloader works correctly without it, you don't need it.batatonana wrote: ↑Mon Jan 20, 2025 2:47 amOther thing I have question about is that most of the implementations of the bootloader and kernel I have is to use a "boot.asm" file to call an external "kernel.c" function. Is this a better practice than calling directly the C function?
-
- Member
- Posts: 801
- Joined: Fri Aug 26, 2016 1:41 pm
- Libera.chat IRC: mpetch
Re: Code is not correct on Kernel entrypoint - custom bootloader
Octocontrabass is correct that you aren't copying your entire kernel to the disk image. You need to round up to the nearest with something like:
You have another problem in bootloader.asm:
You are still running in 16-bit real mode. You will end up loading 0x00011000 into EAX. The problem is that JMP is still a real mode jump. If the CS segment limit is 64KiB then this will cause a #GP fault and will likely hang because 0x11000 is >= 64KiB. It may be the CS segment limit is 4GiB in some cases, or there is no segment limit checking (QEMU doesn't check segment limits for performance reasons) so you may not get a #GP exception and the JMP will work. You are relying on an unknown CPU state that may or may not allow the JMP to work.
Note: In 16-bit real-mode If you can successfully do JMP EAX with an EIP>=0x10000 (64Kib) you can't reliably run with EIP>=0x10000 unless you add a 32-bit operand override to each instruction that reloads EIP. Example: `jmp $` would fail as it would reload EIP and clear the upper 16-bits of EIP yielding a jump to the wrong location. `o32 jmp $` would work. QEMU's software emulation is somewhat non-compliant with the Intel system development manuals so code that appears to work in QEMU may not work on real hardware. The same code may fail if you run QEMU with option `--enable-kvm`. Moral of this story: Don't JMP to an EIP>=0x10000 in 16-bit real mode unless you know what you are doing.
Since you will need to enter 32-bit protected mode before trying to run 32-bit code - entering protected mode with a flat 4GiB memory model for CS/DS/ES/SS (typical) would put the CPU in a state where you can properly JMP to 0x11000 (or any address < 4GiB) without strange side effects.
Code: Select all
dd conv=notrunc if=$(OS) of=$(DISK_IMG) bs=512 count=$$((($(shell stat --printf="%s" $(OS))+511)/512)) seek=1
Code: Select all
; Load the 32 bit addres to jump to
mov si, 0x18
mov eax, dword [es:si]
jmp eax
Note: In 16-bit real-mode If you can successfully do JMP EAX with an EIP>=0x10000 (64Kib) you can't reliably run with EIP>=0x10000 unless you add a 32-bit operand override to each instruction that reloads EIP. Example: `jmp $` would fail as it would reload EIP and clear the upper 16-bits of EIP yielding a jump to the wrong location. `o32 jmp $` would work. QEMU's software emulation is somewhat non-compliant with the Intel system development manuals so code that appears to work in QEMU may not work on real hardware. The same code may fail if you run QEMU with option `--enable-kvm`. Moral of this story: Don't JMP to an EIP>=0x10000 in 16-bit real mode unless you know what you are doing.
Since you will need to enter 32-bit protected mode before trying to run 32-bit code - entering protected mode with a flat 4GiB memory model for CS/DS/ES/SS (typical) would put the CPU in a state where you can properly JMP to 0x11000 (or any address < 4GiB) without strange side effects.
Re: Code is not correct on Kernel entrypoint - custom bootloader
Might be simpler to just leave out the count= argument. Then it'll just keep reading the input file until it ends.MichaelPetch wrote: ↑Mon Jan 20, 2025 5:09 pm Octocontrabass is correct that you aren't copying your entire kernel to the disk image. You need to round up to the nearest with something like:Code: Select all
dd conv=notrunc if=$(OS) of=$(DISK_IMG) bs=512 count=$$((($(shell stat --printf="%s" $(OS))+511)/512)) seek=1
Carpe diem!