DEV Community

Cover image for Writing My Own Boot Loader

Writing My Own Boot Loader

Frank Rosner on November 07, 2020

Series Introduction I have recently watched Preventing the Collapse of Civilization by Jonathan Blow - amazing talk - and was curious if...
Collapse
 
leob profile image
leob • Edited

Really cool, something totally different among all of the web development articles! Used x86 assembly long time ago but only for a few tiny utility programs.

Collapse
 
frosnerd profile image
Frank Rosner

I mean in the end my boot loader is also just a tiny utility program 😅.

TBH I'm glad I don't have to use assembler for more than tiny programs because it requires a lot of mental capacity to even do simple things.

Collapse
 
wiilf24 profile image
C T • Edited

Thank you very much for this! I did the entire process on my own without ever knowing of this article, or osdev. I noticed a few call parameters that I had incorrect in my own build, and your makefile parameters saved the day! I ported the entire project from your GIT to Windows 7 x64 and migrated the Makefile into my modular build scripts. As on Windows, its required to use clang, lld, and objcopy. I also use readelf to dump a report of my ELF file to text file for later review before calling objcopy. I run my build scripts in this way:

1 - Bootloader
2 - Kernel
3 - Disk Image
4 - Emulation (Qemu)

Note the "@eaBIOS" - I just replaced 'X' with '@'.

Image description
Working successfully. Much appreciated ;)

Collapse
 
liam824css profile image
liam824css

what is this erld: warning: cannot find entry symbol start; defaulting to 0000000000001000
ld: kernel.o: in function main':
kernel.c:(.text+0x10): undefined reference to
_GLOBAL_OFFSET_TABLE
'
make: *** [Makefile:9: kernel.bin] Error 1
ror?

Collapse
 
codinggeek1711 profile image
Maheswaran Parameswaran

I know its late but add -fno-pie to gcc compilation

Collapse
 
luidenkagolden profile image
Luidenka-Golden

May I know the code with -fno-pie added?

Thread Thread
 
hecker2007 profile image
Parambir Singh

its --no-pie and not -fno-pie

Collapse
 
frosnerd profile image
Frank Rosner

I don't know? What did you do?

Collapse
 
liam824css profile image
liam824css

I do start makefile

Thread Thread
 
frosnerd profile image
Frank Rosner

I wrote and tested this only on Mac. Are you using Linux?

Thread Thread
 
liam824css profile image
liam824css

yes

Thread Thread
 
luidenkagolden profile image
Luidenka-Golden

same problem in macOS

Collapse
 
havanduc2002 profile image
HaVanDuc2002

Adding -fno-pie in gcc fix the problem to me
gcc -fno-pie -m32 -ffreestanding -c kernel.c -o kernel.o

Collapse
 
imanerd profile image
(っ◔◡◔)っ♥ CRYPTY ♥ • Edited

Hey! This is the best kernel series in the world! I want to make a tutorial about it on YT and a personal OS, basing on this source code. But I don't know if i have the permissions. Thank you, for the great series, and hope you reply me!

Collapse
 
frosnerd profile image
Frank Rosner

Go ahead!

Collapse
 
imanerd profile image
(っ◔◡◔)っ♥ CRYPTY ♥

Thank you!

Thread Thread
 
frosnerd profile image
Frank Rosner

Please share your material once you're done so I can check it out and hit the like button ;)

Thread Thread
 
imanerd profile image
(っ◔◡◔)っ♥ CRYPTY ♥

OK!

Collapse
 
turnerj profile image
James Turner

Great post! I have always wanted to do my own OS though ideally with C# syntax (tried with Cosmos). It is something I want to try again at some stage - build a mini bootloader like you have and initialise an environment to run it.

Kinda like what you seem to get at in the article, I imagine drivers will be the harder part.

Looking forward to the next part!

Collapse
 
frosnerd profile image
Frank Rosner

Glad you liked it! Working on a simple VGA driver right now :)

Collapse
 
mckeep82 profile image
mckeep82

Hi Frank,

I really enjoyed this lesson and have used it to supplement a lesson published by Lucus Darnell in his Operating System from Scratch lessons.

Would I have your permission to use your code base in lessons to my students? I used to have them work with GRUB for their assignments, but having a fully implemented bootloader compatible with qemu would be a great lesson.

Please let me know, thanks!

Collapse
 
frosnerd profile image
Frank Rosner

Sure, go ahead! Do you mind linking folks to this post? :)

Collapse
 
mckeep82 profile image
mckeep82

Absolutely! I will reference the post in the syllabus. Perhaps I can put your information together with some of my other work and put it into an open source text book that we can use to distribute to the students. Would you be interested? Thanks for the response!

Thread Thread
 
frosnerd profile image
Frank Rosner

Absolutely! I will reference the post in the syllabus.

Thanks! Which course is it?

Perhaps I can put your information together with some of my other work and put it into an open source text book that we can use to distribute to the students.

I do not want to invest any time into this right now. My priorities shifted :) wiki.osdev.org has some good resources as well.

Thread Thread
 
mckeep82 profile image
mckeep82

This is for an OS Development course! Also I wouldn't expect anything from you! I would just collect the information in an online source that you could access (if you wanted, you would also be free to entirely ignore it :))

Collapse
 
igortas profile image
Igor Tashevski

My question is, how in the past, OS was build without tooling, like nasm and etc... How for example u will load the kernel main function in the past without linker... How u can build simple bootloader, without this tools, ok maybe QEMU can stay, but without all other tools...

Collapse
 
frosnerd profile image
Frank Rosner

I guess it all started with a programmable computer and then people started building stuff. As soon as somebody "invented" assembler, you could use that to build a C compiler and linker. Then you could rewrite the compiler in C and compile it with the assembly compiler.

People used what they have and in parallel built more tools / abstractions to make it easier to build complex systems. The problem with that is that every layer of abstraction might make it easier to write a piece of software, but it does not make it simpler. The complexity is still there.

And building an operating system is not an easy task. I mean there are thousands of developers busy doing that since decades and you are still lucky if your printer or scanner works...

Collapse
 
darkyelox profile image
darkyelox

Great post, I have learning a lot from it, only two things:

  1. the segment descriptor URL you provided is pointing to nothing or is bad.
  2. You should add Makefile for Linux users in the repo or here in your post, I have tried it in my Po_OS and it didn't work, searching a little I found that for compile the kernel with gcc you should add the -fno-pie parameter and that fixed it now working as expected.

Again great post so far, I'll keep learning from this in the next sections.

Collapse
 
frosnerd profile image
Frank Rosner

the segment descriptor URL you provided is pointing to nothing or is bad.

Fixed, thank you!

You should add Makefile for Linux users in the repo or here in your post, I have tried it in my Po_OS and it didn't work, searching a little I found that for compile the kernel with gcc you should add the -fno-pie parameter and that fixed it now working as expected.

Glad you figured it out :) Happy to accept a PR :)

Collapse
 
hornet512 profile image
Hornet512

When I tried the makefile part this is what I got:
Makefile:9: *** missing separator. Stop.

Collapse
 
frosnerd profile image
Frank Rosner • Edited

Hm... Might be that I screwed something up there. You could check the source code for a version that was at least working on my Mac.

If you find the problem feel free to report back so I can fix it :)

Collapse
 
liam824css profile image
liam824css

kernel-entry.o : kernel-entry.asm
nasm $
^
|
Erase this blank and write a tab

Collapse
 
retrocomputers profile image
RetroComputers • Edited

Im using windows 10 and ubuntu on wsl and makefile dosent work and i am pretty new to makefiles. Can i find ubuntu version of makefile anywhere or how to "build" this manually?

Collapse
 
frosnerd profile image
Frank Rosner

Have you tried dev.to/seanld/comment/1fi4k? It's a shame that noone submitted a pull request to fix it, yet.

Collapse
 
retrocomputers profile image
RetroComputers

Yeah i have fixed that but i get this message
"nasm mbr.asm -f bin -o mbr.bin
make: nasm: Command not found
make: *** [Makefile:18: mbr.bin] Error 127"
and i haven't found how to fix it.

Thread Thread
 
retrocomputers profile image
RetroComputers • Edited

I fixed that by putting nasm to path variable but i got another error message that say " cannot perform PE operations on non PE output file 'kernel.bin'." Somehow the make file did run without errors but the screen flickers and start over.

Thread Thread
 
frosnerd profile image
Frank Rosner

Yeah welcome to OS development :D Dealing with stuff that doesn't work as expected was my daily routine when I wrote this series :)

Thread Thread
 
retrocomputers profile image
RetroComputers

Yeah, i will try to troubleshoot it but thanks for responses.

Collapse
 
exzdev profile image
Ezra

I ran it on a Windows 11 environment, and encountered problems when doing the linker.
nasm boot/boot.asm -f bin -o bin/boot.bin
nasm boot/kernel-entry.asm -f elf -o libs/kernel-entry.o
gcc -m32 -ffreestanding -c kernel/kernel.c -o libs/kernel.o
ld -m elf_i386 -o bin/kernel.bin -Ttext 0x1000 libs/kernel-entry.o libs/kernel.o --oformat binary
ld: unrecognised emulation mode: elf_i386
Supported emulations: i386pe
make: *** [bin/kernel.bin] Error 1

I don't know what I did to cause this problem.

Collapse
 
liam824css profile image
liam824css

makefile is error
my os is ubuntu and how makefile start?
console:makefile:9: *** missing separator. Stop.
why?

Collapse
 
frosnerd profile image
Frank Rosner

I wrote the makefile on Mac. Never tested it on Ubuntu :)

Collapse
 
liam824css profile image
liam824css

Please test the makefile in Ubuntu and create a new makefile for Ubuntu in the repository.

Thread Thread
 
frosnerd profile image
Frank Rosner

Why don't you do it?

Thread Thread
 
seanld profile image
Sean Wilkerson • Edited

For anyone else following along getting this error, a quick Google shows that makefiles do not like spaces for tabs. So you have to convert all spaced indents to tabbed indents before running make.

Source: stackoverflow.com/questions/169317...

Thread Thread
 
frosnerd profile image
Frank Rosner

Cool! Happy to accept a PR if that helps folks :)

Collapse
 
hanna profile image
Hanna Rose

Great detailed post! Will have to read it later.

Collapse
 
thijmen_roos_531efa981660 profile image
Thijmen Roos

Nice! But when I compile it, with --no-pie, I get this error:
qemu-system-i386: symbol lookup error: /snap/core20/current/lib/x86_64-linux-gnu/libpthread.so.0: undefined symbol: __libc_pthread_init, version GLIBC_PRIVATE
make: *** [Makefile:24: run] Error 127

I know I am a little bit late (like 4 years), but that shouldn't matter, right?

Collapse
 
neverstoptesting profile image
neverstoptesting

Quick question, might be missing something:

You set your bp register to 0x9000 with the explanation that this is the bottom of the stack. We then set the sp register to the same.

Now, since the sp register is at 0x9000, that means that the first push instruction would decrement the sp by 4 and then load the contents at that address (which would be 0x8FFC).

I've been cross referencing this wonderful guide with other web resources. One of them I found was here

eecs.wsu.edu/~cs460/cs560/booter.html

and another

0xax.gitbooks.io/linux-insides/con...

Both of which describe a memory space with a section starting at 0x9000 that can be used for "stack space".

But if we set sp to 0x9000, wouldn't then our push put the SP into the memory space below that, in the kernel reserved space?

If the kernel is light, this probably isn't an issue (I've cloned your repo and added my own C code so I know this works).

However, given the other references, should we not aim to prevent the stack from going into the addresses below 0x9000?

I'd appreciate your insight. Thanks so much.

Collapse
 
kukovdev profile image
KukovDev • Edited

For some reason it doesn't work for me :(

After I combined mbr.bin and kernel.bin -> threw it into ultraiso and specified it as "bootable" -> launched it on qemu, nothing happens. I checked and the problem turned out to be in the kernel boot. For some reason, the disk_error error crashes and infinity loop.

But the post is good! I enjoyed it

Collapse
 
frosnerd profile image
Frank Rosner

Sorry! Yeah the setup appears to be quite flaky :(

Collapse
 
codinggeek1711 profile image
Maheswaran Parameswaran

I have a question, How big were ur binary files?
Once i link kernel_entry and kernel, the binary explodes to 130 mb when the original object files are less than a few thousand kilobytes

Collapse
 
frosnerd profile image
Frank Rosner

I don't remember but it was definitely small enough to fit into the amount of bytes I was reading in my bootloader and I'm pretty sure this wasn't 130 MB. Are you by any chance including the standard library or smth?

Collapse
 
codinggeek1711 profile image
Maheswaran Parameswaran

I fixed that issue... It was a problem as I was not using a cross compiler for compilation and something went weird

Collapse
 
seanld profile image
Sean Wilkerson

This is an awesome article. Thank you Frank! Something about writing code as close to bare-bones as possible makes programming enjoyable again for me. Thanks for being concise, yet informative.

Collapse
 
frosnerd profile image
Frank Rosner

Glad you liked it!

Collapse
 
helowken profile image
helowken

Cool!!! It's much useful for me, thanks very much~~~~

Collapse
 
bugb profile image
bugb

Thank you for your great post!! Keep up your good work!

Collapse
 
henryjw profile image
Henry Williams

Thanks for sharing! I've been looking for some more exposure to systems programming. You've inspired me to also attempt to make an OS from scratch.

Collapse
 
frosnerd profile image
Frank Rosner

Good luck!

Collapse
 
anaktas profile image
Anastasios

One of my favorite posts! Clicking the follow button

Collapse
 
hecker2007 profile image
Parambir Singh

Hi there ! It's running fine with qemu but yes we have to add the--no-pie command while compiling with gcc. The main problem is that it is not working on a real machine and just on qemu

Collapse
 
mitchell_weber_3ba833cae2 profile image
mitchell weber

mine did not write the x any where even though mine is the same

Collapse
 
sayyadnasirkhan profile image
nasirkhan sayyad

how to add welcoming message to the bootloader when load

Collapse
 
frosnerd profile image
Frank Rosner

I leave that as an exercise to you!

Collapse
 
xephoninedeb profile image
Xuan Xylen

hello i am having an issue, in qemu it says:
Boot failed: could not read the boot disk
Booting from floppy

(And takes forever)

Collapse
 
mckeep82 profile image
mckeep82

Do you have the code uploaded to a repository? I could clone it and see what the issue might be.

Collapse
 
_merajhasan profile image
Meraj

Remove -fda in makefile

Collapse
 
mitchell_weber_3ba833cae2 profile image
mitchell weber

@frosnerd i try to make the make file but i get this error makefile.mak:11: *** missing separator. Stop.