Sunday, January 10, 2016

Building the Kernel

Many years ago when I worked for a receipt printer company, I was given the opportunity to write a USB driver for Windows.  It was one of those very fast conversations "anybody want to do this?" and I watched the opportunity pass by as someone else wanted to.  Honestly, it didn't sound very appealing at the time, but ever since then I always wondered what it would take to talk to USB devices.

So I've taken up trying to learn how to do this in a Linux environment.  There are many reasons I believe this is the best use of my time at the moment, not worth going into here.  But the biggest reason is: Stayin Alive.

To get started, the Linux Device Drivers book is free for download (and there's also apparently a 4th edition).  I'm using the 3rd edition for now:

http://free-electrons.com/doc/books/ldd3.pdf

The book wouldn't let me go any further until I had built my own kernel.  And so here we are.


Hardware

Presumably building the kernel can be done on a virtual machine or an AWS ec2 instance or a raspberry pi, but for now I'm using my old dusty iMac, because it already runs Linux Mint (see Recovering Files From A Crashed Mac), and it will build faster than the rPi.

The only downside with using my iMac was a nagging sense of doubt - that it might not work.  I also noticed the Mint distributions are all odd numbered kernel versions, so I assumed they are heavily modified from the main tree.  But I found I was able to actually build the kernel and switch to it and it actually ran fine on this hardware.

For this I got Mint 17.3 32-bit Cinnamon "Rosa", just to try getting the latest.

The process for building is fortunately spelled out: How to: Compile the latest kernels (Classic Mint & LMDE).  This is an excellent guide, even though I ran into some kinks.


The First Kink
Mint 17.3 32-bit Cinnamon Rosa runs vmlinuz-3.19.0-32-generic.  Just look in /boot, or run uname -r.

So browsing to kernel.org, the closest subsequent version was 4.1.15, so I tried downloading and making this, and the make crashed.

At this point, it really helps to have no sense of dignity or pride, no feeling of "am I wasting my time" or "this is clearly not my fate in life".  It really helps to be sort of... dumb.  You know?

So what would a dumb person do?  Follow the example on the forum verbatim of course!

By following the example to the letter, which uses 3.8.7, everything built fine.  Here's my history output which should be exactly what they posted on the forums.

      Note these aren't included but updating everything can't hurt (run as root):

    3  apt-get update
    4  apt-get upgrade
    5  apt-get dist-upgrade


    8  apt-get install build-essential kernel-package libncurses5-dev fakeroot wget bzip2
    9  apt-get install qt4-designer qt4-dev-tools qt4-doc qt4-linguist-tools qt4-qmake
   10  export CONCURRENCY_LEVEL=2
   12  export CFLAGS="-march=native -O2 -pipe"
   13  export CXXFLAGS="$CFLAGS"
   14  export CHOST="x86-pc-Linux-gnu"



     Note: These I ran as a regular user:

   29  wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.8.7.tar.xz
   30  tar -Jxf linux-3.8.7.tar.xz
   31  cd linux-3.8.7
   32  cp /boot/config-3.19.0-32-generic ./.config
   33  make oldconfig
   34  make xconfig
   35  menuconfig
   36  make menuconfig

   40  fakeroot make-kpkg --initrd --append-to-version=-mint-17.3-x86-32-16-01-09-2246 kernel_image kernel_headers
   41  ls ..
   42  cd ..
   43  sudo dpkg -i linux-image-*.deb linux-headers-*.deb
   44  sudo update-grub


Note: I think xconfig never worked for me, so menuconfig was okay, and I changed nothing in it either.

Also the build process (fakeroot make-kpkg...) took well over an hour.


The Second Kink

After rebooting, running uname -r showed the old kernel was still running.  This is because the grub apparently will run whatever the most up-to-date kernel available is.  To fix this, I ran:

  gksudo gedit /etc/default/grub

and commented out the hidden timeout references so it looked like this:

  GRUB_DEFAULT=0
  #GRUB_HIDDEN_TIMEOUT=0
  #GRUB_HIDDEN_TIMEOUT_QUIET=true
  GRUB_TIMEOUT=10
  GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
  GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
  GRUB_CMDLINE_LINUX=""


This allowed a selection menu to show up at boot.  The "advanced" menu allowed selecting the older kernel I had built.

Display Driver Issues
Lastly, just booting into that kernel didn't work because the iMac's nVidia drivers don't run.  So instead, select the "recover mode" version of the kernel, and after that boots up run the first option (something like "resume") which bypasses hardware video support altogether.  I'm writing this blog post from that build right now.  Note that the forum also explains in the same thread how to run the nVidia driver after first running:

   update-initramfs -k `uname -r`

(note the ` character not ' as the forum says).  I started to try this, didn't know where to get the nvidia driver and more importantly, I don't care.  This is adequate functionality to move forward with the Linux Driver book.

Thanks!


PostScript

Right after posting this, I tried hybernating the machine, which resulted in severe problems with booting up that kernel (even when it had already booted twice).  Specifically, the initrd.img* file for the built kernel is somehow missing.  I was able to fix this by running dpkg and update-grub again (after renaming things dpkg complained about) - but I have no explanation how the initrd.img* file got deleted.   So this whole approach is somewhat unstable for now.


Wifi Drivers


For a Mac, to get Wireless working, try this.  Namely, connect via an Ethernet cable, and run these commands:

 sudo apt-get purge bcmwl-kernel-source broadcom-sta-common broadcom-sta-source
 sudo apt-get install linux-firmware-nonfree b43-fwcutter firmware-b43-installer

and then reboot.

No comments:

Post a Comment