Skip to content

dklibc/whll

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

=WHLL //Linux x86 PC Bootloader=

WHLL -- White Horse Linux Loader. My own Linux kernel bootloader for x86 PC.
As simple as hummer. I started to write it in the middle of the Jan,2016 and
finished in the middle of Feb. Why did I need yet another linux bootloader?
Since I dislike GRUB and LILO. <STRONG>I always think
that bootloader should be as simple as possible</STRONG>, but they make it with
hundreds of config options and supporting of several file systems. There is a
special util to edit GRUB2 configs, LOL. They should add MySQL dependency!

Why "White Horse"? Couse than I often drank cheap scotch "White Horse".
That time I thouhgt that writing your own Linux bootloader was cool. And I also
had an experience in coding bootloaders in asm. 

First time I wanted to add support of reading EXT2 like GRUB, but this seemed
hard to do, so I started to inspect LILO. LILO loads kernel from file system,
but knows nothing about file system internals. How? Special util creates file
where kernel block numbers are stored, each block of this file also stores a
number of the next block, a number of the first block is stored in LILO body.
This way LILO knows what disk blocks it needs to load. Simple and elegant. But
after each modification of the kernel file you need to remake this LILO file
with block numbers. But how we get to know in which block on disk which file
block is resided? Linux has the special syscall -- <TT>fbmap</TT>, that doing
this job. I tested it, but I don't like it.

Cause I always think that a bootloader should be as simple as possible, so it's
bad to make bootloader to know file system internals. So, I made this decision:
bootloader and kernel should be on the separate disk partition with no file
system.

NOTE: the first two 512-byte sectors in EXT2 partition are reserved for
bootloader code. So, bootloader developers need to fit their code that knows
EXT2 internals in only 1KB! Tip: they can compress bootloader code and
decompress it in memory on the fly.

I decided that my bootloader won't print long descriptive messages. Since they
occupies a lot of space, but I wanted to fit my bootloader in 512 bytes. In
this case it doesn't need to load its rest from the disk. I implemented the way
LILO does: after each completed stage it prints a char in the next console
position, in case of error it prints 'E'. Doing this way we can get to know
a stage where booting fails. After each successful loaded kernel block
bootloader prints '-', so you can see that all goes fine (this is worth while
you are debugging).

I use FASM. I really like it. Code of v1 fit in 512 bytes. 

I got to know that Linux kernels has several formats (two?) And they are
different in booting protocol. The first Linux kernels were small and fit in
low 640KB of PC memory. The modern kernels are larger 1MB and needed to be
loaded into extended memory (above the first MB). But this addresses you can't
just read/write in the real mode of x86. I use "unreal" mode of x86 to access
them.

I chose to implement boot protocol version 2.2, since kernel 2.4 uses it.
More recent kernels I hadn't used before.

For loading disk sectors my bootloader uses BIOS int 0x13 LBA functions.

The bootloader worked fine from the first run -- I'm fucking cool!

==v1.1==

After year on Dec,29 (sic!) I needed to add to the bootloader support
of loading the second kernel and giving command line to a kernel. What for?
It's worth to be capable to load working kernel in case of new freshly compiled
one failed to boot. And by means of command line you can say init process:
"Hey! Boot in the single-user maintanance mode"

I spent only one day to implement this. I didn't made any corrections in the
existing bootloader code, I only added new functions. A new code exceeded
512-byte limit -- it was approx 855 bytes long. So, it needs to load the first
sector from disk byself.

==Install==

* Create separate disk partition
* Write the bootloader from the sector #0 of that partition
* Write a kernel starting from sector #2
* Optional: write the second kernel to the offset 5000 sectors from the
begining (my current 2.6 kernel size is approx 2480 sectors, so
reservation of the 5000 sectors will be enough for the long time)
* Done!

==Usage==

If you need to load the second kernel or give a kernel a command line, you
should quickly press a F3 key multiple times until you see a
bootloader greetings. A bootloader will ask you if you want to load the second
kernel. Say 'y' if you need. Next you can input command line. You can use
a Backspace key to edit it.