Compiling Kernel code in Linux - c

Okay, I'm reading about Linux kernel development and there are some code snippets using kernel's data structures and stuff. Let's say I'd like to experiment with them, e.g. there's a very simple snippet:
#include <../../linux-2.6.37.1/include/linux/sched.h>
struct task_struct *task;
for_each_process(task) {
printk("%s[%d]\n", task->comm, task->pid);
}
Seems pretty simple, eh? Now then, I can't possibly build the thing. I am using NetBeans. The sched.h is the correct file as if one can CTRL+clicks on it, one is brought to the right file.
Do I need to include somehow my sample file and build the whole kernel from the Makefile? I just wished to see that it builds and possibly that it would work. If I need to build the whole kernel how would I actually test my stuff?
I must be making something really stupid as I am very new to kernel development. I am quite a bit lost.
Thanks guys!

You do not need to compile the whole kernel, but you have to at least create a kernel module, which is far easier to compile. You should have a look at a tutorial, such as this, or even a full blown book like this.
Keep in mind that not all kernel code can be moved to a module - just those that use the public (exported) interfaces of the kernel. Code that is intrinsic to the kernel core parts (e.g. the VM or the scheduler) is probably inaccessible from the rest of the kernel.
Also keep in mind that trying out kernel code on your development machine is not advised - a
slight mistake can easily bring the whole system down. You should look at trying out your kernel code in a separate virtual machine e.g. in VirtualBox.
A detail that makes thing harder: in general you can only insert a module in the kernel that it was built for. A module compiled on the host system can be used on the testing VM if and only if the kernel is identical, i.e. the same kernel package version from the same distribution. Considering that you will want to upgrade your host distribution, in my opinion it is just simpler to build the module on the testing system.
Since you need a full development suite for C, you should probably install one of the popular Linux distrbutions. It should be more stable and you can have access to its user community. If you want to keep its size down, you can just install the base system without an X server or graphical applications.
BTW Netbeans is designed to develop userspace applications. You can probably adapt it for kernel code, but it will never be as suited as it is for userspace programming. As a matter of fact, no IDE is really suitable. Kernel code cannot be run from userspace (let alone using a separate VM), which breaks down the normal edit->compile->run->debug workflow cycle that IDEs automate.
Most kernel developers just use a souped-up editor with syntax highlighting for C, such as Vim or Emacs. Emacs is actually an IDE (and so much more) but, as I mentioned above, you cannot easily use an IDE-based workflow for kernel code development.

You can build a loadable kernel module if you don't want to build the whole kernel - e.g. see http://www.linux-tutorial.info/modules.php?name=Howto&pagename=Module-HOWTO.

All the code you write, compile and run as user programs run as ... well, user programs, in user mode. The kernel runs in kernel mode. Both modes are separated and cannot see each other directly. They communicate through defined interfaces. These interfaces are the C system calls (as opposed to the C library calls).
To be able to access the task_struct structures, your code has to be running in kernel mode. The best choice for this is to write a kernel module, and to load it in the kernel.

Very little kernel code can run outside the kernel in any form. Most kernel code is very 'intertwingled' (to use a phrase I learned from a coworker years ago to describe excessive coupling) with other portions of kernel code. Functions 'know' structure definitions for many many structures away from what they are working on. Typical software engineering people hate code like this:
if (unlikely(inode_init_always(sb, inode))) {
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
else
kmem_cache_free(inode_cachep, inode);
return NULL;
}
This routine has to know how to destroy inodes through three structures and the calling convention of a function pointer on the other end of the chain. The kernel community knows all these functions very well, and are quite happy to modify member names in structures all throughout the kernel when changes are made, but this sort of tight coupling makes running portions of the kernel in userspace on their own extremely difficult. (And believe me, sometimes I wish I could write tests on my small portions of kernel code that would run in userspace.)
If you want to play around, it's not too hard to get a virtual system up and running these days with qemu+kvm or virtualbox or uml to try making modifications to the kernel. It is pretty hard to just "play" with structures on a live running system, but it is much more feasible than trying to compile portions of the kernel in userspace.
Good luck. :)

You might enjoy using systemtap as a wrapper for small bits of kernel module code:
# stap -g -e 'probe begin { your_function() exit() }
%{
#include <linux/whatever.h>
%}
function your_function() %{
... insert safe c code here ...
%}'
It can automatically cross-compile too (if you use stap --remote=VIRTMACHINE ...).

Related

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.

Making a new filesystem

I'm looking to make a custom filesystem for a project I'm working on. Currently I am looking at writing it in Python combined with fusepy, but it got me wondering how a compiled non-userspace filesystem is made in Linux. Are there specific libraries that you need to work with or functions you need to implement for the mount command to work properly. Overall I'm not sure how the entire process works.
Yup you'd be programming to the kernel interfaces, specifically the VFS layer at a minimum. Edit Better link [1]
'Full' documentation is in the kernel tree: http://www.mjmwired.net/kernel/Documentation/filesystems/vfs.txt. Of course, the fuse kernel module is programmed to exactly the same interface
This, however, is not what you'd call a library. It is a kernel component and intrinsically there, so the kernel doesn't have to know how a filesystem is implemented to work with one.
[1] google was wrong: the first hit wasn't the best :)
If you'd like to write it in Python, fuse is a good option. There are lots of tutorials for this, such as the one here: http://sourceforge.net/apps/mediawiki/fuse/index.php?title=FUSE_Python_tutorial
In short: Linux is a monolithic kernel with some module-loading capabilities. That means that every kernel feature (filesystems, scheduler, drivers, memory management, etc.) is part of the one big program called Linux. Loadable modules are just a specialized way of run-time linking, which allows the user to pick those features as needed, but they're all still developed mostly as a single program.
So, to create a new filesystem, you just add new C source code files to the kernel code, defining the operations your filesystem has to perform. Then, create an initialization function that allocates a new instance of the VFS structure, fills it with the appropriate function pointers and registers with the VFS.
Note that FUSE is nothing more than a userlevel accessible API to do the same, so the FUSE hooks correspond (roughly) to the VFS operations.

Standalone application in C, a good idea?

The term has several definition according to Wikipedia, however what I'm really interested in is creating a program that has all its needed dependencies included within the source folder, so the end user doesn't need to install additional libraries for the app to install. For example, how Mac apps has all its dependencies all within the program itself already...
or is there a function that autotools does this? I'm programming in the Linux environment...
Are you talking about the source code of your application, or about your application binary?
The answer I'd give for both the cases depends on what libraries you're using.
If you're using libraries that you can find anywhere, that are somehow standard and/or that are quite big, you shouldn't attach them to your application, just require them both to build and to run your application.
Anyway don't be much concerned about your source code: little people will build your application, and they probably know something about programming and how a Linux system works; it won't be a big deal to require many (also not-so-common) dependences to build your application.
For what concerns the binary version it could be a little more problematic, since it will be used by end users who often don't know anything about libraries and programming stuff: you could choose to statically link the smallest and most uncommon libraries to your binary, in order to have less dependences.
You could do it, if you link statically, but it'd be somewhat unusual, and depending on what your program is supposed to do, you might be limiting yourself.
The alternative, if this is not just a one-off project, is to create a Linux Standard Base compatible RPM package and restrict yourself to linking against the libraries and symbols that LSB defines.
Run ldd on your program to discover all dependencies, then copy these to your directory, and add a program-wrapper script that issues
#!/bin/sh
LD_LIBRARY_PATH="${0##*/}:$LD_LIBRARY_PATH" exec "${0##*/}/real-program" "$#";
Duplicating the Mac OS X .app behavior on a plain POSIX system is difficult because it is very hard to guarantee that a process can find it's own executable (there are several way that will almost always work...). Mac OS X provides a OS service for this, but Linux (for instance) does not.
Once you've accomplished that feat, this becomes possible. Though, as others have mentioned, it loses the ability to share resource demands (disk space, RAM space, cache space) with other programs that use the same libraries because you'd be using static copies, or dynamically loading your own copy from the .app-like bundle.

What alternative environments exist for building projects?

I was looking at the Linux From Scratch project awhile ago and was sort of disapointed that you needed an existing copy of Linux on your machine to build it. I know that Linux is very easy to obtain, install, etc. but I was hoping to build the LFS project outside of the modern operating systems (Unix/Linux/OS-X/Windows/Etc.) and in something like DOS.
My question is, how might I build a project whether it be C, C++ or some other language with a C compiler, without building that project within another operating system. By operating system I mean Unix, Linux, OS-X, Windows, and every other GUI capable 'modern-ish' OS.
So specifically I'm looking for something that works much like DOS. I'm not above using DOS if thats all that is available, however I'm thinking something that has the ability to use all available memory, processing power, etc. I want to start my computer and be welcomed by a "prompt" from which I can build or execute a program (like another Operating System).
In order to build a program you need to: execute other programs (compiler, linker), access a filesystem both for reading the code and writing out the compiled files, and so on. You need a "real" operating system, even more so if you want to "use all available memory" and processing power. If you don't like the "high level appearence" of GUI capable OSes, just try one of the many stripped-down linux distros: for instance, "damn small linux" comes to mind.
I think the closest you're going to come is a Gentoo Linux Stage 1 install. It basically gives you a prompt and then you compile EVERYTHING, including the kernel, from that minimal starting point. It's about as close as you're going to get without keying in the binary for the bootloader by hand ;)
My guess is, it will be lots of work, but this DOS compiler may help DJGPP. Minix may also be an option, but it does have X Windows. Beyond that, you are going to be hard pressed to find anything.

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...

Resources