Building a "Kernel" in PCI Expansion ROM

Intro

This article is positioned as the official documentation of my Operating System On a PCI Expansion ROM project. Previously, this file is only a change log to the OS source code distribution, but later I decide to make it a complete article and here we are now :). Due to this "history", every detail explanation in this article will use the OS source code as its reference. You can download the latest source code distribution in the attachment of this article (scroll to the end of the article to see the link to download it).

The current source code distribution is a makefile based source code. Hence, it's not very easy to comprehend how the source code works. Also, there are several things that need to be explained pertaining to how the code gets executed, as this OS is not like the current "conventional Operating System" which is loaded from HDD or other types of "conventional Boot Device".

Preliminary Information About The Code

To fully comprehend the explanations int this article, you have to be good at the following subjects:

These stuff would help you better understand what actually happen here :).

The source code actually built a two stage kernel boot loader. It changes the direction of booting from LAN facility in your computer BIOS into booting your own routine inside of the flashrom/eeprom of your LAN card or another card that you hack into a " LAN card indisguise", to be used to boot your kernel which is located inside the flashrom. A more thorough explanation about expansion ROM can be be found in the 2nd section of my "Preliminary BIOS Modification Guide" article.

How The Code Works

The principle of the execution of the code is based upon the BEV(Bootstrap Entry Vector) mechanism as explained in the Plug and Play BIOS Spec 1.0A.

Some important terms :

The basic run-down of what happens as follows:

If you are new to this subject, then you might need the PCI specification 2.1 or newer and the Plug And Play BIOS Specification v1.0A so that the explanation here will be more obvious.

There is one thing that still obscure here: How exactly the BEV executed? is the system bios jump into it directly in the PCI device address space (in ROM) that's mapped into the system address space or the system bios load the entire expansion rom to RAM and execute the BEV in RAM ? This is still a mystery to be solved.

That's all for the current code version.

I plan to port all of the nasm code to GAS in the future and integrate the whole code using GNU tools so that I can use linker script to ease code maintenance. I hope this explanation is enough to someone that might read this.

"Shocking" fact about PCI Expansion ROM

Recently, I'm frustrated to find a flash rom chip for my new realtek RTL8139 NIC to continue my "OS_in_PCI_Expansion-ROM" project. Being unable to find such a chip that would work with my new card, I came across the idea of really hacking a different kind of PCI card that initially have flash rom chip from it's manufacturer to ease the continuation of my project. PCI spec 2.1 and 2.2 also the PnP Bios Boot spec says that the motherboard BIOS boot from LAN feature "only" (read--not so sure until I try it) checks the feature from the expansion ROM of the "NIC" (he..he.. or a "hacked into NIC" PCI expansion card) and proceeds accordingly, through int 19h interface (please correct me if I'm wrong). Then the hypothetical conclusion is this:

"ANY PCI expansion card can boot just like a typical bootable LAN Card provided we have the 'right' PCI expansion ROM BIOS".

So, I give it a try, since I don't have another cheap solution to this problem. And voila', it works very nicely, the mainboard BIOS is fooled to boot from my hacked PCI expansion rom card, here's the detail: Adaptec AHA-2940U SCSI controller card (VendorID = 9004, DeviceID = 8178), with soldered PLCC SST29C512 flashrom (64KByte). The binary flashed using unnoficial flash program (flash4.exe). The result is awesome and a bit weird, no matter how I changed the BIOS setup, the PCI initialization routine always get called during POST. I think this is due to the controller's chip Subclass Code and Interface Code, which is a SCSI controller/boot device in the Adaptec controller chip (AICXXX). Hence, it's always called by the mainboard BIOS at boot. The hacked BIOS make it behave as if it's a real PCI NIC except for the peculiarity mentioned above, my system boot from the card (through it's BEV routine) if I select boot from LAN in the BIOS setup of my mainboard. One thing to notice is I've changed the PCI vendor ID and device ID to match the ID's in the adaptec controller chip from my previous OS source code (for the Realtek based NIC), otherwise it won't boot (I think this what would happen, I haven't try this ).

Successfully "Hacked" PCI CARDs

The following cards have been successfully "implanted" with the resulting binary from this source code with little modification(s):

Building The OS from The Latest Source Code

The latest source code distribution already supported compilation using makefile. You only need to invoke:

make

in the main/root directory of the source code distribution to make the OS and invoke :

make clean

to clean up all of the files generated.

Note: You have to provide the following program in an executable path within your "shell":

I used Linux (with bash shell) as my development environment, and it works just fine. I've tried using MinGW32 and MSys and the makefile works just fine but I don't know why gcc unable to output the "pure binary" file of the kernel (kernel.bin) correctly. If you have any suggestion please mail me.

Building The OS From Scratch (a Detailed Insight into The Source Code Structure)

This is the explanation of how to build the very first version which place all the source files in one directory. It is cumbersome, but it works. It is still here to give insight of how actually the code works. Rather than reading all the "twisty" makefile, it's better to read this file to know how exactly this thing works.

The following guide explains how to build a working "very simple kernel" from the sources in one directory.

Step 0: The assumptions in the following steps

Step 1: Build the tools needed

The sources needed to build all of the tools are provided in the utility directory. If you are using gcc, then just invoke it as follows (for each file):

     

gcc [source_filename] -o [target_filename]

Explanation of the tools

zeroextend [input_filename] 1024

Step 2: Build the kernel loader

The source files are in the loader directory. Here's the explanation of the files :

To build the kernel loader, proceed with the following steps :

nasm -fbin [filename] -o [target filename]

       mergebin loader1.bin loader2.bin loader.bin

Step 3: Build the C kernel code

Compile and link the C sources for the kernel which are located in the kernel directory. To do so, invoke the following command:

gcc -c video.c -o video.o

gcc -c ports.c -o ports.o

ld -o kernel.bin -Ttext 0x7E00 -e main -N --oformat binary main.o video.o ports.o

Note: The last line means, link the files with main() function as entry point, with plain binary format and the code will begin at 0x7E00 when executed, since the first 512 bytes from 0x7C00 is used by loader2.bin, and with no page alignment (one page is 4Kbyte).

We're not done yet !!!

Then use zeroextend utility to extend the file into multiple of 512 bytes (since we're building a ROM file here d00d) as follows:

      zeroextend kernel.bin 1024

Note: I'm using 1024 bytes as the "extended" file size for the C kernel binary here.

Step 4: Merge the kernel loader and the C kernel

Merge the C compiled code (kernel.bin) and the assembly code (loader.bin). Invoke the following command:

mergebin loader.bin kernel.bin boot.bin

Note: Again, take care of the position of the parameters! mergebin is sensitive to it.

Step 5: Patch the needed checksums

Invoke the following command:

      patch2pnprom boot.bin

to patch all the wrong checksums in the binary so that boot.bin will become a valid ROM file. This file is the "ready to burn ROM file", use rtflash or another flashing tool to burn it into your LAN/NIC card (or another PCI expansion card) flash rom chip.

Yeah, we're done. I believe that the majority of the reader of this article is people who attracted in OS development. Thus, I assume that you are a programmer and just let the source code speak for additional technical information. I'm pretty much busy lately, so I haven't been able to continue the development of this experimental OS.

-- Update --

For more complete explanation, go to this article.

-- 31 Jan 2017 Update --

The Expansion ROM OS code is now hosted in GitHub: https://github.com/pinczakko/PCI-Expansion-ROM-OS

Copyright © Darmawan M S a.k.a Pinczakko