How to create bootable application image (efi)? - c

I trying to boot an elf microkernel in an UEFI environment. So i compiled a minimal boot loader and created an ESP image. This works fine if I boot via an HDD but I want to direct boot it via the qemu -kernel option (This is some special requirement as I am working with AMD SEV). This doesn't work.
I can boot my kernel like this with grub if I use grub mkimage with a fat image included i.e. like this:
mcopy -i "${basedir}/disk.fat" -- "${basedir}/kernel" ::kernel
mcopy -i "${basedir}/disk.fat" -- "${basedir}/module" ::module
grub-mkimage -O x86_64-efi
-c "${basedir}/grub-bootstrap.cfg"
-m "${basedir}/disk.fat"
-o "${basedir}/grub.efi"
But the goal for my system is minimalism and security hence the microkernel, so grub and it's vulnerabilities is out of question.
So my question is:
How to create a bootable application image similar to grub-mkimage?
I have read about efi stub boot but couldn't really figure out how to build an efi stub image.
Normally I am a bare metal embedded programmer, so the whole uefi boot thing is a bit weird to me. I am glad for any tips or recommendations. Also I figured stack overflow might not be the best place for such low level questions, can you maybe recommend other forums?

I want to direct boot it via the qemu -kernel option
Why? It's a qemu-specific hack that doesn't exist on anything else (including any real computer). By using this hack the only thing you're doing is failing to test anything you'd normally use to boot (and therefore failing to test anything that actually matters).
(This is some special requirement as I am working with AMD SEV)
That doesn't make any sense (it's a little bit like saying "I have a banana in my ear because I'm trying to learn how to play piano").
AMD's SEV is a set of extensions intended to enhance the security of virtual machines that has nothing at all to do with how you boot (or whether you boot from BIOS or UEFI or a qemu-specific hack).
I am glad for any tips or recommendations.
My recommendation is to stop using GRUB specific (multi-boot), Qemu specific (-kernel) and Linux/Unix specific (elf) tools and actually try to use UEFI. This will require you to write your own boot loader using (Microsoft's) PE32+ file format that uses UEFI's services itself. Note that GNU's tools (their "Gnu-EFI" stuff for GCC) is relatively awful (it puts a PE32+ wrapper around an ELF file and does run-time patching to make the resulting Franken-monster work); and there are much better alternatives now (e.g. the Clang/LLVM/lld toolchain).
If you care about security, then it'll also involve learning about UEFI SecureBoot (and key management, and digital signatures). If you care about secure virtual machines I'd also recommend learning about the SKINIT instruction from AMD"s manual (used to create a dynamic root of trust after boot); but don't forget that this is AMD specific and won't work on any Intel CPU, and is mostly obsolete (the "trusted measurement" stuff from BIOS and TPM was mostly superseded by SecureBoot anyway), and (even on Intel CPUs) if you're only the guest then the hyper-visor can emulate it in any way it wants (and it won't guarantee anything is secure).
Finally; note that booting a micro-kernel directly doesn't make much sense either. There's no device drivers in a micro-kernel; so after booting a micro-kernel you end up with a "can't start any device drivers because there are no device drivers" problem. Instead you need to load many files (e.g. maybe an initial RAM disk), then (e.g.) start some kind of "boot log handler" (to display error messages, etc); then find and start the kernel, then start other processes (e.g. "device manager" to detect devices and drivers; "VFS layer" to handle file systems and file IO; etc). For the whole thing; starting the kernel is just one relatively insignificant small step (not much more than starting a global shared library that provides multi-tasking) buried among a significantly larger amount of code that does all the work.
Sadly; booting a monolithic kernel directly can make sense because it can contain all the drivers (or at least, has enough built into the kernel's executable file to handle an initial RAM disk if it's "modular monolithic" with dynamically loaded drivers); and this "monolithic with stuff that doesn't belong in any micro-kernel" idea is what most beginner tutorials assume.

Related

How to make a program run by BIOS?

I searched for info about this but didn't find anything.
The idea is:
If I code a program in C, or any other languages, what else do I need to do for it to get recognized in BIOS and started by it as a DOS program or just a prompt program?
I got this idea after I booted an flash drive with windows using the ISO and Rufus, which put some code in the flash drive for the BIOS to recognize it and run, so I would like to do the same with a program of mine, for example.
Thanks in advance!
An interesting, but rather challenging exercise!
The BIOS will fetch a specific zone from the boot device, called a master boot record. In a "normal" situation with an OS and one or more partitions, the MBR will need to figure out where to find the OS, load that into memory, and pass control to it. At that time the regular boot sequence starts and somewhat later the OS will be running and be able to interact with you. More detail on the initial activities can be found here
Now, for educational purposes, this is not strictly necessary. You could write an MBR that just reads in a fixed part of the disk (the BIOS has functions that will allow you to read raw sectors off a disk, a disk can be considered as just a bunch of sectors each containing 512 bytes of information) and starts that code. You can find an open source MBR here and basically in any open source OS.
That was the "easy" part, because now you probably want to do something interesting. Unless you want to interact with each part of the hardware yourself, you will have to rely on the services provided by the BIOS to interact with keyboard, screen and disk. The traditionally best source about BIOS services is Ralf Brown's interrupt list.
One specific consideration: your C compiler comes with a standard library, and that library will need a specific OS for many of its operations (eg, to perform output to the screen, it will ask the operating system to perform that output, and the OS will typically use the BIOS or some direct access to the hardware to perform that task). So, in going the route explained above, you will also need to figure out a way to replace these services by some that use the BIOS and nothing more - ie, more or less rewrite the standard library.
In short, to arrive at something usable, you will be writing the essential parts of an operating system...
Actually BIOS is going to be dead in the next two years (INTEL will not support any BIOSes after this date) so you may want to learn UEFI standard. UEFI from v2.4 allows to write and add custom UEFI applications. (BTW the "traditional" BIOS settings on the UEFI computers is often implemented as a custom UEFI App).

Run executable on MINI2440 with NO OS

I have Fedora installed on my PC and I have a Friendly ARM Mini2440 board. I have successfully installed Linux kernel and everything is working. Now I have some image processing program, which I want to run on the board without OS. The only process running on board should be my program. And in that program how can I access the on board camera to take image from, and serial port to send output to the PC.
You're talking about what is often called a bare-metal environment. Google can help you, for example here. In a bare-metal environment you have to have a good understanding of your hardware because you have to take care of a lot of things that the OS normally handles.
I've been working (off and on) on bare-metal support for my ELLCC cross development tool-chain. I have the ARM implementation pretty far along but there is still quite a bit of work to do. I have written about some of my experiences on my blog.
First off, you have to get your program started. You'll need to write some start-up code, usually in assembly, to handle the initialization of the processor as it comes out of reset (or is powered on). The start-up code then typically passes control to code written in C that ultimately directly or indirectly calls your main() function. Getting to main() is a huge step in your bare-metal adventure!
Next, you need to decide how to support your hardware's I/O devices which in your case include the camera and serial port. How much of the standard C (or C++) library does your image processing require? You might need to add some support for functions like printf() or malloc() that normally need some kind of OS support. A simple "hello world" would be a good thing to try next.
ELLCC has examples of various levels of ARM bare-metal in the examples directory. They range from a simple main() up to and including MMU and TCP/IP support. The source for all of it can be browsed here.
I started writing this before I left for work this morning and didn't have time to finish. Both dwelch and Clifford had good suggestions. A bootloader might make your job a lot simpler and documentation on your hardware is crucial.
First you must realise that without an OS, you are responsible for bringing the board up from reset including configuring the PLL and SDRAM, and also for the driver code for every device on the board you wish to use. To do that required adequate documentation of the board and it devices.
It is possible that you can use the existing bootloader to configure the core and SDRAM, but that may not meet your requirement for the only process running on the board should be your image processing program.
Additionally you will need some means of loading and bootstrapping; again the existing Linux bootstrapper may suit.
It is by no means straightforward and cannot really be described in detail here.

How to write a custom kernel on mac?

I've been following the "Mike OS Guide" to make my own kernel, and I got it working. But then I went onto the many guides on the internet for making a boot sector in NASM that loads a main function from a compiled C object. I have tried compiling and linking with all kinds of GCC installations:
x86_64-pc-linux-
arm-uclinux-elf-
arm-agb-elf-
arm-elf-
arm-apple-darwin10-
powerpc-apple-darwin10-
i686-apple-darwin10-
i586-pc-linux-
i386-elf-
All of them fail once I put them onto a floppy like I do with the MikeOS bootstrap. I've tried various tutorials on http://www.osdever.net/ like the one here and I've tried http://wiki.osdev.org/Bare_Bones , but none work when trying to compile on a Mac, yet I have not tired on an actual Linux machine yet. But I was wondering how I could get a bootstrap in assembly the calls the C function and put them together into a working kernel file and then load the onto a floppy file then onto an ISO like in the MikeOS tutorial. Or should I just make the kernel.bin and load it with syslinux? Could anyone give me a tip on how to make this all work on a Mac developement environment? I have tolls via macports and homebrew so that helps. Anyone successively done this?
EDIT
Here's my bootsector so far.
I just wanna know how to jump to an extern function from the C and link it.
There's a few problems with this. First of all, all the compilers you mentioned output either 32-bit or 64-bit code. That's great, but when the boot sector starts, it's running in 16-bit real mode. If you want to be able to run that 32-bit or 64-bit code, you'll need to first switch to the appropriate mode (32-bit protected mode for, well, 32-bit, and long mode for 64-bit).
Then, once you switch to the appropriate mode, you don't even have that much space for code: boot sectors are 512 bytes; two bytes are reserved for the bootable signature, and you'll need some bytes for the code that switches to the appropriate mode. If you want to be able to use partitions on that disk or maybe a FAT filesystem, take away even more usable bytes. You simply won't have enough space for all but the most trivial program.
So how do real operating systems deal with that? Real operating systems tend to use the boot sector to load a bigger bootloader from the disk. Then that bigger bootloader can load the actual kernel and switch to the appropriate mode (although that might be the responsibility of the loaded kernel — it depends).
It can be a lot of work to write a bootloader, so rather than rolling your own, you may want to use GRUB and have your kernel comply to the Multiboot standard. GRUB is a bootloader which will be able to load your kernel from the disk (probably in ELF format) and jump to the entry point in 32-bit protected mode. Helpful, right?
This does not free you from learning assembly, though: The entry point of the kernel must be assembly. Often, all it does is set up a little stack and pass the appropriate registers to a C function with the correct calling convention.
You may think that you can just copy that rather than writing it yourself, and you'd be right, but it doesn't end there. You also need assembly for (at least):
Loading a new global descriptor table.
Handling interrupts.
Using non-memory-mapped I/O ports.
…and so on, not to mention that if you have to debug, you may not have a nice debugger; instead, you'll have to look at disassemblies, register values, and memory dumps. Even if your code is compiled from C, you'll have to know what the underlying assembly does or you won't be able to debug it.
In summary, your main problem is not knowing assembly. As stated before, assembly is essential for operating system development. Once you know assembly thoroughly, then you may be able to start writing an operating system.

How can the Linux kernel compile itself?

I don't quite understand the compiling process of the Linux kernel when I install
a Linux system on my machine.
Here are some things that confused me:
The kernel is written in C, however how did the kernel get compiled without a compiler installed?
If the C compiler is installed on my machine before the kernel is compiled, how can the compiler itself get compiled without a compiler installed?
I was so confused for a couple of days, thanks for the response.
The first round of binaries for your Linux box were built on some other Linux box (probably).
The binaries for the first Linux system were built on some other platform.
The binaries for that computer can trace their root back to an original system that was built on yet another platform.
...
Push this far enough, and you find compilers built with more primitive tools, which were in turn built on machines other than their host.
...
Keep pushing and you find computers built so that their instructions could be entered by setting switches on the front panel of the machine.
Very cool stuff.
The rule is "build the tools to build the tools to build the tools...". Very much like the tools which run our physical environment. Also known as "pulling yourself up by the bootstraps".
I think you should distinguish between:
compile, v: To use a compiler to process source code and produce executable code [1].
and
install, v: To connect, set up or prepare something for use [2].
Compilation produces binary executables from source code. Installation merely puts those binary executables in the right place to run them later. So, installation and use do not require compilation if the binaries are available. Think about ”compile” and “install” like about “cook” and “serve”, correspondingly.
Now, your questions:
The kernel is written in C, however how did the kernel get compiled without a compiler installed?
The kernel cannot be compiled without a compiler, but it can be installed from a compiled binary.
Usually, when you install an operating system, you install an pre-compiled kernel (binary executable). It was compiled by someone else. And only if you want to compile the kernel yourself, you need the source and the compiler, and all the other tools.
Even in ”source-based” distributions like gentoo you start from running a compiled binary.
So, you can live your entire life without compiling kernels, because you have them compiled by someone else.
If the C compiler is installed on my machine before the kernel is compiled, how can the compiler itself get compiled without a compiler installed?
The compiler cannot be run if there is no kernel (OS). So one has to install a compiled kernel to run the compiler, but does not need to compile the kernel himself.
Again, the most common practice is to install compiled binaries of the compiler, and use them to compile anything else (including the compiler itself and the kernel).
Now, chicken and egg problem. The first binary is compiled by someone else... See an excellent answer by dmckee.
The term describing this phenomenon is bootstrapping, it's an interesting concept to read up on. If you think about embedded development, it becomes clear that a lot of devices, say alarm clocks, microwaves, remote controls, that require software aren't powerful enough to compile their own software. In fact, these sorts of devices typically don't have enough resources to run anything remotely as complicated as a compiler.
Their software is developed on a desktop machine and then copied once it's been compiled.
If this sort of thing interests you, an article that comes to mind off the top of my head is: Reflections on Trusting Trust (pdf), it's a classic and a fun read.
The kernel doesn't compile itself -- it's compiled by a C compiler in userspace. In most CPU architectures, the CPU has a number of bits in special registers that represent what privileges the code currently running has. In x86, these are the current privilege level bits (CPL) in the code segment (CS) register. If the CPL bits are 00, the code is said to be running in security ring 0, also known as kernel mode. If the CPL bits are 11, the code is said to be running in security ring 3, also known as user mode. The other two combinations, 01 and 10 (security rings 1 and 2 respectively) are seldom used.
The rules about what code can and can't do in user mode versus kernel mode are rather complicated, but suffice to say, user mode has severely reduced privileges.
Now, when people talk about the kernel of an operating system, they're referring to the portions of the OS's code that get to run in kernel mode with elevated privileges. Generally, the kernel authors try to keep the kernel as small as possible for security reasons, so that code which doesn't need extra privileges doesn't have them.
The C compiler is one example of such a program -- it doesn't need the extra privileges offered by kernel mode, so it runs in user mode, like most other programs.
In the case of Linux, the kernel consists of two parts: the source code of the kernel, and the compiled executable of the kernel. Any machine with a C compiler can compile the kernel from the source code into the binary image. The question, then, is what to do with that binary image.
When you install Linux on a new system, you're installing a precompiled binary image, usually from either physical media (such as a CD DVD) or from the network. The BIOS will load the (binary image of the) kernel's bootloader from the media or network, and then the bootloader will install the (binary image of the) kernel onto your hard disk. Then, when you reboot, the BIOS loads the kernel's bootloader from your hard disk, and the bootloader loads the kernel into memory, and you're off and running.
If you want to recompile your own kernel, that's a little trickier, but it can be done.
Which one was there first? the chicken or the egg?
Eggs have been around since the time of the dinosaurs..
..some confuse everything by saying chickens are actually descendants of the great beasts.. long story short: The technology (Egg) was existent prior to the Current product (Chicken)
You need a kernel to build a kernel, i.e. you build one with the other.
The first kernel can be anything you want (preferably something sensible that can create your desired end product ^__^)
This tutorial from Bran's Kernel Development teaches you to develop and build a smallish kernel which you can then test with a Virtual Machine of your choice.
Meaning: you write and compile a kernel someplace, and read it on an empty (no OS) virtual machine.
What happens with those Linux installs follows the same idea with added complexity.
It's not turtles all the way down. Just like you say, you can't compile an operating system that has never been compiled before on a system that's running that operating system. Similarly, at least the very first build of a compiler must be done on another compiler (and usually some subsequent builds too, if that first build turns out not to be able to compile its own source code just yet).
I think the very first Linux kernels were compiled on a Minix box, though I'm not certain about that. GCC was available at the time. One of the very early goals of many operating systems is to run a compiler well enough to compile their own source code. Going further, the first compiler was almost certainly written in assembly language. The first assemblers were written by those poor folks who had to write in raw machine code.
You may want to check out the Linux From Scratch project. You actually build two systems in the book: a "temporary system" that is built on a system you didn't build yourself, and then the "LFS system" that is built on your temporary system. The way the book is currently written, you actually build the temporary system on another Linux box, but in theory you could adapt it to build the temporary system on a completely different OS.
If I am understanding your question correctly. The kernel isn't "compiling itself" these days. Most Linux distributions today provide system installation through a linux live cd. The kernel is loaded from the CD into memory and operates as it would normally as if it were installed to disk. With a linux environment up and running on your system it is easy to just commit the necessary files to your disk.
If you were talking about the bootstrapping issue; dmckee summed it up pretty nice.
Just offering another possibility...

Developing kernels and testing them in virtual machines

I like programming challenges, and writing a kernel seems a programming challenge.
Unfortunately, kernels are particularly hard to test because they are basically the core of operating systems and so they can't be easily ran on top of an operating system.
However, I know about applications called Virtual Machines that can emulate computer hardware.
What is the easiest/best way to develop and test kernels(C+Assembly) using Virtual Machines?
While BOCHS seems to be better at letting you know when something goes horribly wrong with your pet OS... it is very slooooow! I use VirtualPC for general purpose testing and BOCHS when things get murky.
Also, you will more than likely be booting the OS every 2 minutes, so it helps to have some sort of automated way to build a boot image & fire off the Virtual PC.
I built a GRUB boot floppy image with all the necessary stuff to get it to boot the Kernel.Bin from the root. I use a batch file to copy this file to the virtual project directory, use FAT Image Generator to copy my kernel to the image. Then just launch the VirtualPC project. Vola!
Excerpt from my batch file:
COPY Images\Base.vfd Images\Boot.vfd /Y
fat_imgen.exe modify Images\Boot.vfd -f Source\Bin\KERNEL.BIN
COPY Images\Boot.vfd Emulators\VirtualPC\ /Y
START Emulators\VirtualPC\MyOS.vmc
One last suggestion: Set the VirtualPC process priority to low - trust me on this one!
I'd be happy to exchange some code!
Tools: DGJPP, NASM, GRUB.
Code: osdev.org, osdever.net
You might be interested in looking at HelenOS. Its a from scratch microkernel that has been ported to many architectures (boots just fine on bare metal) developed using simulators such as Simics and QEMU.
We use a static grub that is copied to the final ISO during the build process. Some things just have to be that way until the OS becomes self hosting. I highly recommend NOT implementing your own userspace C library unless you really do want to do everything from scratch .. you'll become self hosting much sooner :)
Though Simics is non-free, I highly recommend it (and its built in debugging/profiling tools) while making your kernel. Once you have some kind of kernel console and logger in place, QEMU does a very nice job.
It's straightforward. Set up a virtual machine, write your kernel, copy it to the virtual machine, boot the virtual machine.
You'll need to be more specific if you want more specific advice.
Probably just setting up a machine (x86, I guess), and then investigate exactly how it behaves during boot. There should be one or more files in the host machine's file system that act as the virtual machine's file system, and then you'd need to put some boot sector information there that causes your in-development kernel to boot.
That would of course mean that the build system on the host has a way to write the kernel to the virtual machine's file system, which might vary in difficulty.
Picking one at random, bochs seems to support editing the boot media from the outside using standard tools like dd etc.
The first question that you need to ask yourself is what hardware architecture are you targeting? I'll assume for the sake of this discussion that you are targeting the IA_32 architecture, which would probably be a wise choice as there is plenty of readily-available documentation on that processor.
If you're truly serious about this undertaking, then you will definitely want to run your debug/code/build/deploy cycle against an emulator or VM. Someone mentioned BOCHS, which is very popular. If emulation speed is your thing, there is also an emulator called Qemu that is faster than BOCHS.
I'd suggest that your development environment run under Linux or Windows, which again would probably be a wise choice due to the available documentation for those dev environments.
Make is your friend. Use it to automate the build/execute process. I'd advise you to pick your toolsets/compilers up front, and spend some time learning them well. It will save you in the long run.

Resources