Tag Archives: linux

Quick-and-dirty partition resize with Acronis True Image

A little embedded Linux magic comes in unexpectedly handy. Years ago, I started using Acronis True Image to back up my office PC. Other backup packages are available, as they say, but it’s worked well enough for me. This week I had reason to use it in earnest.

img_20180619_112420

The PC is set up with two main partitions on the disk. There’s one for the operating system (Windows 10) and applications, and another with data on it, analogous to the /home partition on a Linux system. Inevitably, it turned out that the boundary between these partitions was in the wrong place. The operating system partition was full, and things were starting to fail. Time to make sure the backup is up-to-date and then to restore to differently-sized partitions.

The operation fell at the first hurdle. Acronis True Image will create a ‘recovery’ USB stick from which the PC boots. This contains a small Linux distribution (Acronis Linux) and a GUI for managing the recovery operation. My backups are on a network drive, which happens to be an Apple Time Capsule. Would the Acronis recovery system connect to the Time Capsule? Would it ever. I couldn’t even persuade it to ask for the username and password, though it could see the Time Capsule on the network.

In Acronis Linux, pressing ctrl-alt-F2 in time-honoured fashion brings up a command line. Yay! Power! A bit of digging reveals a command called asamba which can connect to SMB shares. Using that, I could connect to the Time Capsule absolutely fine and mount it to the local filesystem. So why couldn’t the GUI do it? Annoying.

My next trick was to copy the backup from the Time Capsule to a USB hard drive using another Linux PC. It took a while for the several hundred gigabytes, but it got there. Acronis recovery will read USB drives, so the next step should be easy, right? No. My USB drive happened to be formatted ext4. Though Acronis Linux is perfectly capable of mounting ext4 filesystems, the recovery GUI only acknowledges the presence of FAT and NTFS discs. Aargh!

The solution was to mount the USB drive on my Linux PC, then share it using Samba. Acronis recovery found and let me log on to the Samba share, and could thus see the drive and backups.

Changing the partition sizes was the next problem. The GUI only allows you to shrink partitions or to grow them in to free space. My disk didn’t have any free space. It was all partitioned and in use. I thought that shrinking the data partition would create free space that the operating system partition could grow in to, but I was caught out by the presence of a 500MB ‘recovery’ partition which Windows had sneaked in between the two. I don’t know what it’s for but I didn’t feel like taking the risk of destroying it. There are no tools in the Acronis GUI for deleting partitions and starting again, so I was stuck.

img_20180619_113338

Command line to the rescue! Ctrl-alt-F2 again, and there’s a perfectly good copy of fdisk available. It was a moment’s work to delete the existing recovery and data partitions, then ctrl-alt-F1 to the GUI. Restart the restore process and there’s free space available for the operating system partition to grow in to, and plenty of room to create new recovery and data partitions.

img_20180619_112939

The restore took a few hours, as expected, but was successful. The only wrinkle was that Acronis recovery had marked the recovery partition as active rather than the boot partition, so the PC complained that there was no operating system. Another trip in to fdisk to mark the boot partition active sorted that out, and now I’m typing this very text on the PC restored to working order.

Footnote: there is another Acronis restore tool intended for restoring backups to dissimilar hardware. This may have handled the partition resizing more elegantly, but I didn’t try it.

Cracking a password-protected PDF file

Suppose you asked an insurance company for a letter. The insurance company kindly sent it as a PDF attached to an email. Sensibly, they protected that PDF with a password which they told you over the phone. You wrote it in a notebook and then left the notebook at work over the weekend.

pdf-password

How could you read the letter in the password-protected file at home, then? Remembering that the password was definitely an English word, and all in lower case, a dictionary attack has got to be worth a try.

Linux provides some handy tools for this. There’s a list of English words in /usr/share/dict/words, and a suite of PDF tools which can attempt to open the file using a password, indicating success or failure. A few minutes with Python and:

#!/usr/bin/python
import os,sys

wf=open('/usr/share/dict/words','r')
while True:
  word = wf.readline().strip().lower()
  if word == '':
    print "No solution found"
    break
  print word
  cmdline = 'pdftotext -upw "'+word+'" '+sys.argv[1]
  result = os.system(cmdline)
  if result == 0:
    break

The same thing must be possible in a more hipsterly fashion using awk, but I couldn’t be bothered to figure out a sufficiently baroque command line.

By the way, the password was ‘orange’. Don’t tell anybody.

Systemd for Embedded Linux

Over the last few years, there has been a lot of controversy in the Linux world about systemd. As I understand it, systemd is intended to be a better-engineered, more powerful version of the motley collection of little programs and scripts which keeps the essential services on a Linux system running.

systemctl

The controversy arises because the original 1970s Unix way of doing things was to rely on a motley collection of little programs and scripts for everything, each of which was simple but well understood, and to knit them together to form a complete operating system. Systemd takes a different approach, using larger and more sophisticated components which are more dedicated to particular tasks, such as managing services or network connections. This is supposed to make it more efficient and easier to manage in the twenty-first century.

I’ve been doing some work recently on an embedded Linux system which runs on the latest version of Debian Linux, version 8 (‘Jessie’). Debian Jessie fully supports systemd to the extent that it seems to be the default way of doing things. I thought I’d experiment with it a bit.

When working on an embedded Linux system, I very frequently want to have a piece of my software run reliably at startup, get restarted if it fails, and be able to output logging information to an easily-managed place. In this case, my software provides a D-Bus interface to a piece of industrial electronics.

In the past I’ve relied on copying and pasting scripts from other pieces of software, and managing log files has always been a bit of a mess. It’s hard to do these things right, so re-inventing the wheel is too risky, which means that the best strategy is to copy somebody else’s scripts. I have never counted the hours of my time which have been wasted by dealing with awkward corner cases and peculiar bugs due to recycled scripts behaving in ways I hadn’t anticipated.

What does it look like with systemd? There are some helpful tutorials out there, including this one from Alexander Patrakov, so it didn’t take me too long to put together a service file which looks like this:

[Unit]
Description=My D-Bus Gateway
[Service]
Type=dbus
BusName=com.martin-jones.gateway
ExecStart=/usr/bin/my_dbus_gateway
Restart=always
[Install]
WantedBy=multi-user.target

I’ve changed the names to protect the innocent, but the contents of the file are pretty self-explanatory. The [Unit] section just includes a description which is readable to a human being. The [Service] section describes the service itself. In this case it’s of type  dbus, which means that systemd will check that the service name (com.martin-jones.gateway in this case) gets correctly published on to D-Bus. The Restart=always setting means that my software gets restarted if it exits. The [Install] section just indicates that this service should run when the system comes up in multi-user mode (like the old runlevel 5).

Having created this file, I simply copied it into /etc/systemd/system/my_dbus_gateway.service and, lo and behold, my new service worked. It was immediately possible to manage the service using commands like

systemctl start my_dbus_gateway.service
systemctl stop my_dbus_gateway.service
systemctl status my_dbus_gateway.service

Great! That’s exactly what I wanted.

Now for logging. I’d heard that systemd would log the stdout and stderr outputs of services into its own journal, and forward that to syslog as required. It does, but there’s a subtlety. Output from stderr appears in /var/log/syslog immediately line-by-line, but output from stdout gets aggressively buffered. This means that it gives the appearance of not working at all unless you explicitly flush the stdout buffer in your code using something like

fflush(stdout)

That’s the only wrinkle I came across, though.

In summary, using systemd’s facilities has made my life as an embedded Linux developer much, much easier and hopefully more reliable. That’s a good thing. My top tips for getting your software working under systemd are these:

  • Create your .service file using the recipe above and the documentation
  • Don’t forget to flush stdout if you want to see it in syslog.

Dealing with Shellshock on Debian Squeeze for ARM

Today’s announcement of the Shellshock Bash vulnerability had me worried. I run lots of Debian Linux systems, and they’re not all the latest version. Many are still Debian Squeeze (version 6) which no longer gets security updates as standard. That’s my fault, of course, and I should have upgraded, but I haven’t. Yet. Now I’m more motivated to do it. However, upgrading to Debian Wheezy (version 7) isn’t something I wanted to do in a hurry, especially on remote machines.

Debian have thought of people like me, and there is a ‘Long Term Support‘ option for Debian Squeeze, which is great, and includes the necessary security update to Bash. The trouble is, it only supports i386 and amd64 processors, and the machines I’m worried about are ARM (specifically armel) ones.

I was left with one option: build the new Bash from source. Fortunately, Debian Squeeze LTS has the source available, so I was able to do this. Here’s how. This might be useful to other Debian ARM users who are none too fastidious about keeping up to date.

I added the line

deb-src http://http.debian.net/debian squeeze-lts main contrib non-free

to /etc/apt/sources.list, and did

apt-get update
apt-get source bash

which fetched the source code. Then I had to build it.

cd bash-4.1
dpkg-buildpackage -b -us -uc

This complained bitterly about a load of missing dependencies, which I dealt with:

sudo apt-get install autoconf autotools-dev bison libncurses5-dev debhelper texi2html gettext sharutils texlive-latex-base ghostscript

which was a royal pain due to lack of disc space. Beware, these packages want about 180MB of disc space (plus about 80MB for the package downloads) so might need some care on a small system. I started by installing packages individually, doing ‘apt-get clean’ after each one, but texlive-latex-base is an absolute monster and I had to do some filesystem reshuffling to get it to install. I hope you don’t have to.

During the build (repeating the dpkg-buildpackage command above) the patch for ‘CVE-2014-6271‘ was mentioned, which was reassuring. The actual build process took a while – about half an hour on a 1GHz-ish ARM chip (a SheevaPlug).

The build completed successfully, so I was able to install the new package:

cd ..
sudo dpkg -i bash_4.1-3+deb6u1_armel.deb

and then start a new shell and try the test:

env X="() { :;} ; echo busted" `which bash` -c "echo completed"

on a ‘broken’ version of Bash, this will print

busted
completed

but on a fixed one, it prints

/bin/bash: warning: X: ignoring function definition attempt
/bin/bash: error importing function definition for `X'
completed

which is the right answer, and means that the vulnerability is patched. It worked!

I hear that the fix isn’t complete, though, so more work may be required later.

Orange Livebox 2.0, port forwarding and NAT loopback

For several years, I’ve been running a small server (a Sheevaplug, as it happens) connected to my home broadband connection. It’s not running anything public, but it’s simply handy to have somewhere I can log in to and do things with from anywhere on the internet. It used to be connected via Virgin Media’s cable broadband service, using an Apple Time Capsule as a router, and a dynamic DNS service to handle the name lookup, and it all worked just fine. I could access my server from computers both inside and outside the house.

Recently I moved house, and the new place has broadband provided by Telekomunikacja Polska masquerading as Orange. Their broadband deal comes with its own router which also provides the VoIP phone service as well as having something to do with the TV. It’s a Livebox 2.0. It would probably be possible to set up a different router to do the same job, but the thought of getting the VoIP stuff to work is too awful to contemplate.

livebox-2

The Livebox 2.0 is a fairly flexible box, and I managed to set it up to forward traffic on one port to my server. The server has a little script which updates its dynamic DNS entry, and that did exactly what it said on the tin. I could log in to the server from elsewhere on the internet. But could I connect to the server’s public IP address from inside the house? No way. The router just reported ‘no route to host’. This was annoying. I have various things set up on my laptop which assume they’ll be able to connect to my server, and to have those not work when I’m at home would be a real pain.

The problem seemed to be that the Livebox didn’t want to route traffic from the internal network, where my laptop was, to its external IP address. Reading Wikipedia on NAT, it turns out that this is a feature called NAT loopback. I didn’t even know it was possible for routers not to support it, but I learn something every day. The Orange Livebox 2.0 won’t do it (and yes, I played exhaustively with all the security/firewalling/port forwarding options).

This called for a workaround. My server has a DNS entry with a dynamic DNS provider. Let’s call it server.dyn.com (it’s not, actually). This resolves to whatever the external IP address of my router happens to be – let’s say 203.0.113.1. From inside my home network, the router makes a mess of handling traffic to 203.0.113.1 so I can’t contact it. However, I have control of DNS on the home network: it’s one of the services on my Sheevaplug. I know that ‘spoofing’ DNS entries is bad practice, but I’m going to do it anyway. I can add entries to my local DNS server which make server.dyn.com look up to 192.168.1.10, the local address of the server. The laptop won’t know the difference, but it’ll be able to contact the server. And outside the home network, there’s no chance of anyone, including me, accidentally contacting my DNS server because there’s no way for traffic to get to it. Here’s a picture.

Img_6117s

I use bind9 as my internal DNS server. I added a section to /etc/bind/named.conf.local:

zone "dyn.com" {
  type master;
  file "/etc/bind/db.dyn.com";
};

and then created another file /etc/bind/db.dyn.com:

$ORIGIN .
$TTL 604800 ; 1 week
dyn.com IN SOA localhost. root.localhost. (
  2009060801 ; serial
  604800 ; refresh (1 week)
  86400 ; retry (1 day)
  2419200 ; expire (4 weeks)
  604800 ; minimum (1 week)
  )
  NS sheevaplug
$ORIGIN dyn.com
example A 192.168.1.10

It worked! At home, example.dyn.com resolves to 192.168.1.10, and out on the internet, it resolves to 203.0.113.1. I think it’s far from perfect – the timing settings on my dyn.com record probably need to be made shorter, so that the laptop doesn’t hang on to them when I leave home, and this setup means that all other subdomains of dyn.com don’t work, but it’s good enough for me for now. Maybe it’ll be helpful for you too.

Installing balloonboard.org Debian Linux build on a Raspberry Pi

I’ve just successfully got Debian Linux running on a Raspberry Pi, having built it entirely from the balloonboard.org distribution. Why might you want to do this? Well, I did it because it gives me a small, clean Debian Linux installation which I can then customise. Here’s how I did it.

Get the software:

svn checkout svn://balloonboard.org/balloon/branches/menuconfig2
make menuconfig
  • Mode Expert mode
  • Balloon Board Raspberry Pi board
  • Choose which buildroot version to build -> Feb 2013
  • Select kernel version 3.8 (rpi)
  • Select Build boot image
  • Select Build kernel modules
  • Select Build initrd kernel
  • Select Build Raspberry Pi boot patition image
  • Select Build Debian Root Filesystem

Now type make and it should all build.

Create yourself an SD card with two partitions on it: one smallish FAT partition for the boot files, and a big ext4 one for the root filesystem. Don’t forget to format them.

Into the FAT partition copy the contents of build/kernel/rpi-initrd-boot. Into the ext4 partition untar the file build/rootfs/debianrootstrap.modules.tgz.

Now put the SD card into your Pi and switch it on. This should boot into a ‘recovery kernel’ which has a minimal root filesystem in its initial ramdisk, just enough to sort out the ‘proper’ root filesystem. I used the console serial port to work with it. The HDMI and USB ports might also work but I haven’t tried them. It should come up with a login prompt. Log in as root, password rootme.

Now to configure the root filesystem:

mount /dev/mmcblk0p2 /mnt/root
chroot /mnt/root

Finish the Debian installation (this has to be done now because some aspects of it need to run on the ARM processor, so it’s not easy to have your PC do it). It will ask you questions about time zones and things:

/var/lib/dpkg/info/dash.preinst install
dpkg --configure -a

Set a password for the root account so you can log in

passwd root

and add the serial port to the list of secure ports which are considered safe for root logins:

echo /dev/ttyAMA0 >> /etc/securetty

And shut things down

halt

That last step will probably produce an error message, but it doesn’t matter as long as it’s written everything to the SD card.

Now put the SD card back in your PC, and copy the contents of build/kernel/rpi-boot into the FAT partition. That contains the real kernel which will mount the newly-minted root filesystem. Put it back into the Pi and boot. It will ask you to change the root password at first login.

It worked for me, though I had to ‘ifdown eth0’ and ‘ifup eth0’ again to get Ethernet to work. From that point on I was able to install Debian packages normally.

How to get the second Raspberry Pi I2C bus to work

One of the useful interfaces on the Raspberry Pi is the I2C bus. Originally invented by Philips in the 1970s for controlling functions inside consumer electronics, especially TVs, it’s still very handy for connecting up lowish-speed peripherals to computers. Some of the most popular are real time clocks like the MCP7940, amongst many others, and general purpose input-output chips like the venerable PCF8574. One of its convenient features is that it only involves two wires: SCL (clock) and SDA (data).

pi2c

The Raspberry Pi originally exposed one I2C bus on its GPIO connector, P1. It had another I2C bus dedicated to the camera connector, S5. However, with revision 2 of the Raspberry Pi, another connector was added. This was P5, squeezed in next to P1, and it also carried the second I2C bus, making it easier to get at and use. However, for some reason the two I2C buses got swapped over between revision 1 and revision 2. And to add a further layer of complication, the camera connector and P5 are wired to different GPIO pins on the processor, even though they are both logically the same bus. I’ve tried to summarise the situation in the table below.

Revision 1 Revision 2
GPIO0 SDA0 P1 pin 3 SDA0 S5 pin 13
GPIO1 SCL0 P1 pin 5 SCL0 S5 pin 14
GPIO2 SDA1 S5 pin 13 SDA1 P5 pin 3
GPIO3 SCL1 S5 pin 14 SCL1 P5 pin 4
GPIO28 SDA0 P1 pin 3
GPIO29 SCL0 P1 pin 5

Working on the CUED MDP project recently, I had a need to get the both I2C buses working on a revision 2 Raspberry Pi. There was no problem with the one on P5: typing

i2cdetect -y 1

showed the devices I had connected to it. But

i2cdetect -y 0

showed nothing at all, and examining pins 3 and 5 of P1 showed no activity. Disappointing. After a bit of digging, it seemed to me that the standard Raspberry Pi Linux kernel configures the processor to use GPIO 0 and 1 as I2C bus 0, and GPIO 2 and 3 as I2C bus 1. I wanted the bus on P1 to work, so I needed GPIO 28 and 29 to be my bus 0.

The BCM2835 processor on the Raspberry Pi, like most modern integrated processors, can have its pins programmed to do various different functions. In this case I needed to disable I2C on GPIO 0 and 1 and enable it on GPIO 28 and 29. To do this I enlisted the help of Mike McCauley’s BCM2835 library. It makes reprogramming the GPIOs fairly straightforward.

To install the library on your Raspberry Pi, make sure it’s connected to the internet, then:

wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.26.tar.gz
tar xzvf bcm2835-1.26.tar.gz
cd bcm2835-1.26
./configure
make
sudo make check
sudo make install

By the time you read this, there might be a new version of the library, so check on Mike’s site to see what you’re getting.

The C code to set up the bus looks like this:

#include <bcm2835.h> 

#define BCM2835_GPIO_FSEL_INPT 0 
#define BCM2835_GPIO_FSEL_ALT0 4 

main() {
    bcm2835_init(); 
    bcm2835_gpio_fsel(0, BCM2835_GPIO_FSEL_INPT); 
    bcm2835_gpio_fsel(1, BCM2835_GPIO_FSEL_INPT); 
    bcm2835_gpio_fsel(28, BCM2835_GPIO_FSEL_INPT); 
    bcm2835_gpio_fsel(29, BCM2835_GPIO_FSEL_INPT); 

    bcm2835_gpio_fsel(28, BCM2835_GPIO_FSEL_ALT0); 
    bcm2835_gpio_set_pud(28, BCM2835_GPIO_PUD_UP); 
    bcm2835_gpio_fsel(29, BCM2835_GPIO_FSEL_ALT0); 
    bcm2835_gpio_set_pud(29, BCM2835_GPIO_PUD_UP); 
}

It initialises the library, sets GPIO 0 and 1 as normal inputs (thus disabling their I2C function) and enables GPIO 28 and 29 as alternate function 0 (I2C bus), with pullup enabled. To build it, cut and paste the code into a file. I called it i2c0.c. Then compile it:

cc i2c0.c -o i2c0 -lbcm2835

and run it:

sudo ./i2c0

Now I2C bus 0 will be active on P1. Well, it worked for me. Once the code is compiled, of course, you can just run ‘i2c0’ after booting the Pi.

I realise that in future this will probably be made obsolete by changing the device tree sent to the Linux kernel at boot time, but for now it’s useful!

Cross-building for ARM on Debian squeeze and lenny

I have to support some software running under Debian Linux 5.0 (lenny) on ARM hardware. The operating system on this hardware can’t easily be upgraded because it’s expensive to get at physically, but there is a mechanism for updating the application it runs. This is an interesting problem in maintaining old software. The ‘stable’ releases of Debian have a reputation for being rather infrequent and almost out-of-date by the time they’re released, but in this case, a release every two years is too often! In embedded applications, having the latest and greatest doesn’t matter as long as it works and doesn’t change.

I have recently had to build a new release of the application software for this ARM hardware. My main Linux machine is now running Debian 7.0 (wheezy), which does a great job of cross-building for ARM, but unfortunately the resulting binaries are linked with libstdc++.so.6.0.17. The old lenny machines have version 6.0.10, which is too old to run these binaries.

For those not familiar with Debian Linux, the relevant versions go like this:

5.0 lenny (released February 2009)
6.0 squeeze (released February 2011)
7.0 wheezy (current as of July 2013)

I fiddled around for a while trying to install older libstdc++ packages under wheezy, but found myself in dependency hell, so I decided simply to revive an ancient PC which was already running Debian 6.0 (squeeze) and press it into service for doing the build.

Getting the ARM toolchain installed wasn’t hard. I had to add the line

deb http://ftp.uk.debian.org/emdebian/toolchains squeeze main

to /etc/apt/sources.list, and do

apt-get install g++-4.4-arm-linux-gnueabi

and it all worked. However, the code I was working on depended on a library, which I needed to install in its ARM version. There’s a handy tool, xapt, which will arrange this for you. However, it’s not natively available on squeeze but has been backported from wheezy, so I had to add

deb http://ftp.uk.debian.org/debian-backports squeeze-backports main

to /etc/apt/sources.list. Then

apt-get install -t squeeze-backports xapt
xapt -a armel libxxx-dev

and my library package was built and installed automagically. Nice.

However, this wasn’t enough. It turned out that I really had to build everything on lenny in order to get it to work – it seems that the libstdc++ from wheezy is compatible with squeeze, but neither wheezy nor squeeze is compatible with lenny.

First, I had to set up a lenny machine. This isn’t as easy as it used to be because lenny is no longer supported by Debian, and exists only as an archive. We should be grateful that it’s there at all. I set up a new virtual machine using VirtualBox and downloaded the last lenny netinst CD image (5.0.10) from archive.debian.org. There’s a problem during installation: it asks which Debian package repository it should use, but all of the available choices fail because the lenny packages aren’t there any more. The solution is to select ‘Back’ and allow it to continue without a repository. It complains, but it works. After it had rebooted, I manually edited /etc/apt/sources.list, commenting out the cdrom line and adding a pointer to the archive:

deb http://archive.debian.org/debian-archive/debian/ lenny main

Then I could install the packages I wanted (subversion, scons and other tools). Now to get the cross-building tools. Sorting out the ARM version of gcc wasn’t too hard. I added

deb http://www.emdebian.org/debian lenny main

to sources.list and was able to install gcc-4.3-arm-linux-gnueabi and g++. Apt complains about a lack of signatures, but that doesn’t stop anything working. I still had to get libssl-dev, though. The xapt tool doesn’t exist on Lenny so I had to use apt-cross, a tool which is an earlier attempt at doing the same thing:

apt-get install apt-cross

and add a source entry to /etc/apt/sources.list:

deb-src http://archive.debian.org/debian-archive/debian/ lenny main

then do

apt-cross -a armel -S lenny -u
apt-cross -a armel -S lenny -i libxxx-dev

and everything happened as it should. Now at last I could build my code and, with fingers crossed, run it on my embedded Debian Lenny machine.

I have to say that I think Debian’s support for cross-building is outstandingly good. Tools like apt-cross and xapt make it much easier than it could be, and the work continues with the multiarch project which improves support still further.

BeagleBone Black Debian build from balloonboard.org

The Balloon Board project set out more than a decade ago to produce a high-performance, low-power, open hardware embedded Linux computing platform. It successfully did that, and now thousands of them are in use in all sorts of products all over the world.

One of the major achievements of the project was a build system which could configure, download, patch and build a boot loader, kernel and root filesystem using a relatively simple menu-driven interface. The menu allows the user to select which type of board to build for, and which customisations to apply. These can include custom kernel drivers for a particular application, or a different Linux distribution (Debian and Emdebian are supported). It doesn’t need an especially powerful machine to run on, but can make use of multiple CPU cores to speed up building.

My colleague Nick Bane has recently, in collaboration with Cambridge University Engineering Department, updated the build system so that it can build software for the Raspberry Pi and BeagleBone Black, both of which are somewhat newer hardware than the Balloon Board. This should make it easier to port software and device drivers between the boards without having to start with a completely new development system.

It might also be of interest to developers working with the Raspberry Pi and BeagleBone boards who want a simple, repeatable way to create the necessary software. This is especially important for use in manufactured products, where the process for creating a whole software distribution needs to be well understood.

This page describes my first attempts at building Debian Linux and the kernel for the BeagleBone Black. This is extremely preliminary, and it doesn’t work yet,

Software build options

Get the software:

svn checkout svn://balloonboard.org/balloon/branches/menuconfig2
make menuconfig
  • Mode Expert mode
  • Balloon Board BeagleBone Black
  • Choose which buildroot version to build -> Feb 2013
  • Select kernel version 3.8
  • make kernel-menuconfig
  • Select Kernel Features -> unselect Compile the kernel in Thumb-2 mode
  • make buildroot-menuconfig
  • Package Selection for the target -> Hardware handling -> Misc devices firmwares -> unselect rpi-firmware
  • Hardware handling -> unselect rpi-userland
  • Debian rootfs
  • Select kernel and module installation method -> Build Debian rootfs with kernel modules
make

Create Micro SD card

I used a 2GB card in a USB card reader connected to my Debian Squeeze PC. I created two partitions using fdisk. Partition 1 is a 50MB FAT16 (type 6) partition, and partition 2 is the rest of the card formatted as ext3 (type 83). On my system, the card appeared as /dev/sdc.

sudo mkfs.msdos /dev/sdc1
sudo mkfs.ext3 /dev/sdc2

Copy the files MLO, u-boot.img and uEnv.txt from the BeagleBone USB drive to the FAT partition.

Make uboot image

sudo apt-get install uboot-mkimage

In build/kernel, do

mkimage -A arm -O linux -T kernel -C none -a 0x80008000 -e 0x80008000 -n "Linux" -d ImageBoot uImage

copy uImage into /boot on ext3 partition

copy am335x-boneblack.dtb from /boot on the original BeagleBone Black board into /boot on ext3 partition

The board tries to boot, but kernel dies with a stack dump:

## Booting kernel from Legacy Image at 80007fc0 ...
 Image Name: Linux
 Image Type: ARM Linux Kernel Image (uncompressed)
 Data Size: 8750560 Bytes = 8.3 MiB
 Load Address: 80008000
 Entry Point: 80008000
 Verifying Checksum ... OK
## Flattened Device Tree blob at 80f80000
 Booting using the fdt blob at 0x80f80000
 XIP Kernel Image ... OK
OK
 Using Device Tree in place at 80f80000, end 80f88bac
Starting kernel ...
[ 0.113797] platform 53100000.sham: Cannot lookup hwmod 'sham'
[ 0.114013] platform 53500000.aes: Cannot lookup hwmod 'aes'
[ 0.114792] omap_init_sham: platform not supported
[ 0.114807] omap_init_aes: platform not supported
[ 0.156004] omap2_mbox_probe: platform not supported
[ 0.225933] Unhandled fault: external abort on non-linefetch (0x1028) at 0xf4
[ 0.233938] Internal error: : 1028 [#1] SMP ARM
[ 0.238662] Modules linked in:
[ 0.241861] CPU: 0 Not tainted (3.8.0 #1)
[ 0.246424] PC is at rtc_wait_not_busy+0x14/0x50
[ 0.251241] LR is at omap_rtc_read_time+0x10/0xa4
[ 0.256147] pc : [<c03eee84>] lr : [<c03ef490>] psr: 40000193
[ 0.256147] sp : df053d60 ip : 00000000 fp : c08b0f28
[ 0.268112] r10: df053e18 r9 : c07d31e4 r8 : df2b7000
[ 0.273560] r7 : df2b71c8 r6 : c08b0f28 r5 : c083a9cc r4 : 00000000
[ 0.280365] r3 : f9e3e000 r2 : 00000000 r1 : df053dc4 r0 : df101010
[ 0.287172] Flags: nZcv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kel
[ 0.294880] Control: 10c5387d Table: 80004019 DAC: 00000015
[ 0.300873] Process swapper/0 (pid: 1, stack limit = 0xdf052240)
[ 0.307134] Stack: (0xdf053d60 to 0xdf054000)
[ 0.311684] 3d60: df053dc4 df053dc4 df053dc4 c03ef490 df2b7000 c03ebbd8 c08b0
[ 0.320217] 3d80: df2b7000 c03ec884 00000000 00000000 00000001 df053dc4 00004
[ 0.328746] 3da0: df053df4 c084fcd4 60000113 df2b54b0 00000000 00000000 80000
[ 0.337275] 3dc0: c084fcc4 00000000 00000000 00000000 00000000 00000000 00000
[ 0.345805] 3de0: 00000000 00000000 00000000 c084fe34 c08b0f28 00000000 00000
[ 0.354335] 3e00: 00000000 df101010 c07d31e4 df103640 c08b0f28 c03eba44 dfef0
[ 0.362866] 3e20: 60000113 df101080 df101010 60000113 00000004 60000113 0000c
[ 0.371394] 3e40: df101080 df101000 df101010 c08b0f30 df104cc0 c08b0f2c c07f8
[ 0.379923] 3e60: 00000000 df101044 df2ccb80 c084fe78 c084fdf4 df101010 df104
[ 0.388453] 3e80: c084fdf4 c08af648 c07d31e4 c07ddb14 00000000 c031e1cc c084c
[ 0.396982] 3ea0: df101010 df101044 c084fdf4 c031cf88 df052000 c031d014 00008
[ 0.405510] 3ec0: c084fdf4 c031b66c df045478 df104c80 df052000 df001840 df2c4
[ 0.414040] 3ee0: c0841ea0 c031bf14 c0725ca0 c084fde0 c084fdf4 c084fde0 c0847
[ 0.422570] 3f00: c0860608 c031d5fc c0860608 c084fde0 c07ddb4c 00000007 c086c
[ 0.431102] 3f20: c07ddb4c c07eff94 c07ddb4c c0008858 00000006 00000006 c0780
[ 0.439633] 3f40: 00000000 c07efcac c07eff94 c07ddb4c 000000dd c086060c c07a4
[ 0.448163] 3f60: c0860600 c07ac314 00000006 00000006 c07ac3f0 c0cc8d80 c0570
[ 0.456693] 3f80: c0577e98 00000000 00000000 00000000 00000000 00000000 00004
[ 0.465222] 3fa0: 00000000 00000000 c0577e98 c000e6d8 00000000 00000000 00000
[ 0.473751] 3fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000
[ 0.482280] 3fe0: 00000000 00000000 00000000 00000000 00000013 00000000 b637d
[ 0.490833] [<c03eee84>] (rtc_wait_not_busy+0x14/0x50) from [<c03ef490>] (om)
[ 0.500636] [<c03ef490>] (omap_rtc_read_time+0x10/0xa4) from [<c03ebbd8>] (_)
[ 0.510257] [<c03ebbd8>] (__rtc_read_time+0x58/0x5c) from [<c03ec884>] (rtc_)
[ 0.519423] [<c03ec884>] (rtc_read_time+0x30/0x48) from [<c03ecad4>] (__rtc_)
[ 0.528773] [<c03ecad4>] (__rtc_read_alarm+0x1c/0x290) from [<c03eba44>] (rt)
[ 0.538858] [<c03eba44>] (rtc_device_register+0x140/0x268) from [<c07d3358>])
[ 0.548850] [<c07d3358>] (omap_rtc_probe+0x160/0x3b8) from [<c031e1cc>] (pla)
[ 0.558576] [<c031e1cc>] (platform_drv_probe+0x1c/0x24) from [<c031cdec>] (d)
[ 0.568657] [<c031cdec>] (driver_probe_device+0x80/0x21c) from [<c031d014>] )
[ 0.578459] [<c031d014>] (__driver_attach+0x8c/0x90) from [<c031b66c>] (bus_)
[ 0.587902] [<c031b66c>] (bus_for_each_dev+0x60/0x8c) from [<c031bf14>] (bus)
[ 0.597431] [<c031bf14>] (bus_add_driver+0x178/0x23c) from [<c031d5fc>] (dri)
[ 0.606963] [<c031d5fc>] (driver_register+0x5c/0x150) from [<c031e58c>] (pla)
[ 0.616948] [<c031e58c>] (platform_driver_probe+0x1c/0xa4) from [<c0008858>])
[ 0.626936] [<c0008858>] (do_one_initcall+0x2c/0x164) from [<c07ac314>] (ker)
[ 0.637019] [<c07ac314>] (kernel_init_freeable+0x108/0x1e4) from [<c0577ea4>)
[ 0.646648] [<c0577ea4>] (kernel_init+0xc/0x164) from [<c000e6d8>] (ret_from)
[ 0.655452] Code: e59f6038 e59f5038 e3a04000 e5963000 (e5d32044)
[ 0.661858] ---[ end trace 33e6cc13d62fdb11 ]---
[ 0.666954] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0b
[ 0.666954]

Raspberry Pi portable development system

I’m often away from my lab and need to carry on working, in airports, co-working offices, at customer premises and so on. Of course, I have a laptop, but that only goes so far when you’re working on embedded Linux hardware. I need to be able to take the hardware with me, and work with it.

Recently I’ve been doing some work with the Raspberry Pi. The Pi is normally set up so that you plug a monitor, keyboard and mouse into it and use it as a desktop computer. That’s OK, but inconvenient for travelling with. You can also log in to it over a network, but that’s not a great idea when I have no idea what networking facilities, if any, will be available where I’m working.

My preferred way of talking to embedded systems is old-fashioned: over a serial port. It may not be the fastest, but it’s reliable and need no infrastructure at all. The Raspberry Pi has a serial port on its GPIO connector, pins 8 and 10, and the standard Raspbian Linux distribution has it set up to be a console. That’s just what I want. Now I just needed a way to connect it to my laptop.

As luck would have it, FTDI make some handy USB-to-serial converter cables. The one I chose for this application is the TTL-232R-3V3. They’re available from various places, but I bought mine from Farnell, part number 1329311.

The connector on the FTDI cable has six pins. As delivered, they are

DSC_0485

  1. Black GND
  2. Brown CTS
  3. Red VCC
  4. Orange TXD
  5. Yellow RXD
  6. Green RTS

The pins along the edge of the Raspberry Pi’s GPIO connector go:

2. +5V
4. +5V
6. 0V
8. TXD
10. RXD

Ooh! How convenient. The 5V power input is available next to the serial port. By rearranging the pins on the FTDI cable’s connector, it’s possible to make a cable which will both power the Raspberry Pi from USB and connect the console to the serial port. That’s perfect for mobile use. The cable is easy to modify: the pins are held in by little black plastic tabs which you can gently bend back with a jeweller’s screwdriver, tweezers or a scalpel. The modified cable is wired like this:

DSC_0487

  1. Red +5V
  2. not connected
  3. Black 0V
  4. Yellow TXD
  5. Orange RXD
  6. not connected

The spare brown and green should be cut off or insulated.

It works! I can drive a Raspberry Pi from my laptop with just this one cable. Very handy. Just be careful to plug it in to the right place on your Raspberry Pi’s GPIO connector, right in the corner. Any other location will apply 5 volts to a pin which isn’t expecting it, and could damage your Pi.

DSC_0488

There are a couple of finishing touches, however. I like to be allowed the responsibility of logging in as root, which Raspbian normally has disabled. It may not be good for schoolchildren to be able to do this, but for embedded developers fiddling with kernel drivers, it’s a great time-saver.

To enable root logins on the serial port, you’ll need to:

  • Enable the password on the root account:

Log in as the default user (user name pi, password raspberry), then

sudo passwd root

Then enter your desired root password twice.

  • Enable root login on the serial console:
echo ttyAMA0 >> /etc/securetty

That’s it. You’re all set.