Raspberry Pi: Difference between revisions

From OSDev.wiki
Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content added Content deleted
m (Added reference to 'Booting ARM Linux' bootloader reference)
(→‎Boot-from-serial kernel: fixed two links)
Line 75: Line 75:
The RPi boots the kernel directly form SD card and only from SD card. There is no other option. While devloping this becomes tiresome since one has to constantly swap the SD card from the RPi to a SD card reader and back. Writing the kernel to the SD card over and over also wears out the card. Plus the SD card slot is somewhat fragile, several people have reported that they broke it accidentally. Overall not an ideal solution. So what can we do abou that?
The RPi boots the kernel directly form SD card and only from SD card. There is no other option. While devloping this becomes tiresome since one has to constantly swap the SD card from the RPi to a SD card reader and back. Writing the kernel to the SD card over and over also wears out the card. Plus the SD card slot is somewhat fragile, several people have reported that they broke it accidentally. Overall not an ideal solution. So what can we do abou that?


I've written a small bootloader named [[https://github.com/mrvn/raspbootin|Raspbootin]] based on the Tutorial in C above that loads the real kernel from the serial port. Raspbootin is acompanied by Raspbootcom ([[https://github.com/mrvn/raspbootin|same repository]]) that acts as a boot server and terminal program. Using the two I only need to reboot my RPi to get it to boot the latest kernel. That makes testing both faster and saver for the hardware.
I've written a small bootloader named [https://github.com/mrvn/raspbootin Raspbootin] based on the Tutorial in C above that loads the real kernel from the serial port. Raspbootin is acompanied by Raspbootcom ([https://github.com/mrvn/raspbootin same repository]) that acts as a boot server and terminal program. Using the two I only need to reboot my RPi to get it to boot the latest kernel. That makes testing both faster and saver for the hardware.


Raspbootin is completely transparent for your kernel. It preserves the r0, r1 and r2 registers and ATAGs placed into memory by the GPU for your kernel. So weather you boot your kernel directly from SD Card or with Raspbootin via serial port makes no difference to your code.
Raspbootin is completely transparent for your kernel. It preserves the r0, r1 and r2 registers and ATAGs placed into memory by the GPU for your kernel. So weather you boot your kernel directly from SD Card or with Raspbootin via serial port makes no difference to your code.
Line 84: Line 84:


The boot protocol for Raspbootin is rather simple. Raspbootin first sends 3 breaks (\x03) over the serial line to signal that it is ready to receive a kernel. It then expects the size of the kernel as uint32_t in little endian byte order. After the size it replies with "OK" if the size is acceptable or "SE" if it is too large for it to handle. After "OK" it expects size many bytes representing the kernel. That's it.
The boot protocol for Raspbootin is rather simple. Raspbootin first sends 3 breaks (\x03) over the serial line to signal that it is ready to receive a kernel. It then expects the size of the kernel as uint32_t in little endian byte order. After the size it replies with "OK" if the size is acceptable or "SE" if it is too large for it to handle. After "OK" it expects size many bytes representing the kernel. That's it.



==Parsing ATAGs==
==Parsing ATAGs==

Revision as of 22:27, 8 February 2013

This page is a work in progress.
This page may thus be incomplete. Its content may be changed in the near future.

Intro

This is a tutorial on bare-metal [OS] development on the Raspberry Pi. This tutorial is written specifically for the Raspberry Pi Model B Rev 2 because the author has no other hardware to test on. But so far the models are basically identical for the purpose of this tutorial (Rev 1 has 256MB ram, Model A has no ethernet).

This is the authors very first ARM system and we learn as we write without any prior knowledge about arm. Experience in Linux/Unix (very important) and C/C++ language (incredibly important, including how to use inline asm) is assumed and required. This is not a tutorial about how to build a kernel but a simple intro in how to get started on the RPi.

Materials

You will need a:

  • Raspberry Pi, RPi in short.
  • SD Card to boot from.
  • A SD Card reader so you can write to the SD Card from your developement system.
  • A serial adaptor for the RPi.
  • Power from an external power supply, usb or the serial adaptor.

Serial adaptor

The RPi has 2 serials (UARTs). This tutorial only concerns itself with UART0, called simply UART or serial port. UART1 is ignored from now on. The basic UART onboard uses a 3.3V TTL and is connected to some of the GPIO pins labeled "P1" on the board. x86 PCs and MACs do use 5V TTL so you need some adaptor to convert the TTL. I recommend a USB to TTL Serial Cable - Debug / Console Cable for Raspberry Pi with seperate connectors per lead, like commercial RPi serial adaptor. Which is then connected to the RPi like this.

Note: The serial adaptor I use provides both a 0V and 5V lead (black and red) which provide power to the RPi. No extra power supply is needed besides this.

Preparations

Testing your hardware/serial port

First things first, you're going to want to make sure all your hardware works. Connect your serial adaptor to the RPi and boot up the official Raspian image. The boot process will output to both the serial and the HDMI and will start a getty on the serial. Set up your serial port, however yours works, and open up minicom. Make sure you have flow control turned off. Ensure you can run at 115200 baud, 8N1, which is what the RPi uses.

If you get 'Permission Denied' do NOT become root! This is unnecessary. Instead do:

sudo adduser <user> dialout

This will let your user use serial ports without needing root.

Or do ls -l /dev/ttyS* to find out the group that own the device, then add you into that group under /etc/group (normally the group is uucp)

If you started minicom only after the RPi has booted then simply press return in minicom so the getty will output a fresh login prompt. Otherwise wait for the boot messages to appear. If you don't get any output then connect the RPi to a monitor to check that it actually boots, check your connections and minicom settings.

Building a cross compiler

Like me you are probably using a x86 PC as main machine and want to edit and compile the source on that and the RPi is an ARM cpu so you absoluetly need a cross compiler. But even if you are developing on an ARM system it is still a good idea to build a cross compiler to avoid accidentally mixing stuff from your developement system with your own kernel. Follow the steps from GCC_Cross-Compiler to build your own cross compiler but use:

export TARGET=arm-none-eabi

Now you are ready to start.

Tutorials and examples

  1. Tutorial in assembler (University of Cambridge)
  2. Tutorial in C
  3. Collection of examples and bootloader by dwelch67

Booting the kernel

Do you still have the SD card with the original raspian image on it from when you where testing the hardware above? Great. So you already have a SD card with a boot partition and the required files. If not then download one of the original raspberry boot images and copy them to the SD card.

Now mount the first partition from the SD card and look at it:

bootcode.bin  fixup.dat     kernel.img            start.elf
cmdline.txt   fixup_cd.dat  kernel_cutdown.img    start_cd.elf
config.txt    issue.txt     kernel_emergency.img

When the RPi powers up the ARM cpu is halted and the GPU runs. The GPU loads the bootloader from rom and executes it. That then finds the SD card and loads the bootcode.bin. The bootcode handles the config.txt and cmdline.txt (or does start.elf read that?) and then runs start.elf. start.elf loads the kernel.img at 0x00008000, puts a few opcodes at 0x00000000 and the ATAGS at 0x00000100 and at last the ARM cpu is started. The cpu starts executing at 0x00000000, where it will initialize r0, r1 and r2 and jump to 0x00008000 where the kernel image starts.

So to boot your own kernel simply replace kernel.img with out own, umount, sync, stick the SD card into RPi and turn the power on.

Note: The GPU also initialized the video ouput, detecting the right resolution from the monitor (if hdmi) or from the config.txt and creates a 2x2 pixel framebuffer (red, yellow, blue and cyan pixels) that the hardware scales to fullscreen with color interpolation. So you get rectangle with a nice color fading.

Boot-from-serial kernel

The RPi boots the kernel directly form SD card and only from SD card. There is no other option. While devloping this becomes tiresome since one has to constantly swap the SD card from the RPi to a SD card reader and back. Writing the kernel to the SD card over and over also wears out the card. Plus the SD card slot is somewhat fragile, several people have reported that they broke it accidentally. Overall not an ideal solution. So what can we do abou that?

I've written a small bootloader named Raspbootin based on the Tutorial in C above that loads the real kernel from the serial port. Raspbootin is acompanied by Raspbootcom (same repository) that acts as a boot server and terminal program. Using the two I only need to reboot my RPi to get it to boot the latest kernel. That makes testing both faster and saver for the hardware.

Raspbootin is completely transparent for your kernel. It preserves the r0, r1 and r2 registers and ATAGs placed into memory by the GPU for your kernel. So weather you boot your kernel directly from SD Card or with Raspbootin via serial port makes no difference to your code.

Raspbootin serial protocol

You don't have to care about this unless you want to write your own boot server.

The boot protocol for Raspbootin is rather simple. Raspbootin first sends 3 breaks (\x03) over the serial line to signal that it is ready to receive a kernel. It then expects the size of the kernel as uint32_t in little endian byte order. After the size it replies with "OK" if the size is acceptable or "SE" if it is too large for it to handle. After "OK" it expects size many bytes representing the kernel. That's it.

Parsing ATAGs

Framebuffer support

Interrupts

USB

External references

  1. arm_arm.pdf - general ARM Architecture Reference Manual v6
  2. DDI0301H_arm1176jzfs_r0p7_trm.pdf - More specific ARM for the RPi
  3. [1] - basic toolchain + UART stuff
  4. RPi_Hardware - list of datasheets (and one manual about peripherals on the broadcom chip)
  5. [2] - for mailboxes and video stuff
  6. BCM2835-ARM-Peripherals.pdf - Datasheep for RPi peripherals
  7. Booting ARM Linux - Describes the generic bootloader interface to the ARM port of linux which the RPi bootloader emulates