-
Notifications
You must be signed in to change notification settings - Fork 21
Experimenting with bare metal coding on a Raspberry Pi
License
brianwiddas/pi-baremetal
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Raspberry Pi bare metal experiments =================================== Building -------- The code is known to build on Linux Mint 12 using the arm-linux-gnueabihf versions of the gcc compiler chain (apt-get install arm-linux-gnueabihf-gcc). This is the same version which exists on the Raspbian "Wheezy" distribution, and the code builds on the Rasperry Pi. To build, type "make". make will build a list of dependencies (in make.dep) by examining each of the .c files, then build the object files before linking them into kernel.elf, and turning that into a binary version (kernel.img). IF YOU'RE NOT BUILDING ON A RASPBERRY PI, there is a copy of libgcc.a from gcc 4.6 from the Raspberry Pi in rpi-libgcc. Make will use this by default. If you know the libgcc.a on your compiler is ok (ie, it only contains ARMv6 instructions), you can set "LOCALLIBGCC=1" in the Makefile, or run "make LOCALLIBGCC=1" instead of "make". When building on a Raspberry Pi (specifically, any device with a processor type of "BCM2708"), make will use the libgcc.a which comes with gcc. In both cases, you can override the libgcc filename by running "make LIBGCC=[filename]". However, the default make will probably work just fine. Installing ---------- kernel.img should be copied onto an SD card. The usual Videocore firmware files are also needed (start.elf, bootcode.bin, fixup.dat and config.txt). Optionally, cmdline.txt can be used to set the kernel command line. At the moment, this is just displayed on the screen rather then being used for anything. As the kernel takes up minimal space and has no filesystem requirement, almost any old SD card will do A recent firmware version is required. If the kernel doesn't boot, try the latest firmware files from https://github.com/raspberrypi/firmware/tree/master/boot Code overview ------------- The kernel is loaded into memory at 0x8000 and starts running from that location, at _start in start.s, which sets up a stack, turns on unaligned memory accesses (it makes the memory routines simpler) and calls initsys(). initsys() sets up the memory management unit (MMU) and remaps the kernel to 0xf0000000, its data to 0xc0000000, and maps the physical memory and peripherals to 0x80000000. It then jumps to main() at its new address. main() further initialises memory, along with the led (GPIO16) and framebuffer. If the framebuffer initialisation fails for any reason, an error code is flashed on the LED in a permanent loop (long pause, 2 short flashes in quick succession, then 8 bits. Short flash = 0, long flash = 1. Least significant bit first. See framebuffer.c for the meaning of the errors). The framebuffer is initialised using tag mailbox calls to VideoCore. First, a call is made to read the physical framebuffer size, then a call is made to set the size (physical and virtual) and depth (bits per pixel) and allocate a framebuffer. Finally, the framebuffer's pitch (bytes per pixel line) is read. It appears to be necessary to set the virtual size before allocating the framebuffer, but reading the physical size of the framebuffer returns an apparently sensible value (unless something silly has been set in config.txt). On boot, the virtual size is set to 2x2. If a framebuffer is allocated without reconfiguring the virtual size, the screen will consist of four very large virtual pixels. Coloured red, green, yellow and blue, they produce the "rainbow" startup screen. A very basic text console has been added. This uses the SAA5050 teletext character set (taken from the datasheet: http://www-uxsup.csx.cam.ac.uk/~bjh21/BBCdata/SAA5050.pdf), partly because it looks quite nice and is a neat link to the BBC Micro, and partly because I already have the data from another project. The SAA5050 character set isn't totally ideal. The # [ { ^ } ] ` _ | and \ characters appear as other symbols (pound sign, left arrow, 1/4, up arrow, 3/4, right arrow, long dash, #, double vertical line and 1/2, respectively). Having set up the framebuffer, the kernel then reads the ATAGs data set up by the bootloader and displays it on screen. The ATAGs format is documented here: http://www.simtec.co.uk/products/SWLINUX/files/booting_article.html#d0e428 The ATAGs code will display most of the tags defined on that page, even where they are not obviously relevant to the Raspberry Pi. In practice, it seems the bootloader only sets up a handful of tags. It is possible to configure the bootloader to not set up ATAGs (disable_commandline_tags=1 in config.txt), but doing so will change the kernel's load address, and it will no longer work. Next, the kernel uses the tag mailbox to get various bits of data from Videocore to display on the screen, along with displaying the kernel code and data addresses. The kernel sets up interrupt vectors and enables the ARM timer interrupt. This interrupt is used to flash the OK LED. The kernel checks that it can't write to its own code area, before attempting to jump to 0x02100000, which resuts in a prefetch abort. Finally, in the prefetch abort routine, the kernel enters an infinite sleep loop. Files overview: * Makefile Controls the build process * linkscript Controls the linker - defines what order code appears in the final kernel, and what address it should expect to be loaded * start.s Assembly code to handle kernel entry point, set up a stack and jump to initsys() * initsys.c Set up MMU, remap kernel addresses and jump to main() * barrier.h Contains asm macros for data memory/sync barriers, and full cache flush * main.c Contains main() and tag mailbox examples * atags.c Read and display ATAGs * led.c GPIO/OK LED control * mailbox.c Read/write the mailboxes * framebuffer.c Framebuffer initialisation and text console * teletext.h SAA5050 character set * textutils.c Couple of small routines to convert numbers into text * memutils.c Routines to copy and clear memory areas * divby0.c If a division function in libgcc.a (which might be called by a divide operation somewhere in the code) attempts to divide by zero, the function will call raise(), which is defined in this file * interrupts.c Interrupt handling routines * memory.c Memory management
About
Experimenting with bare metal coding on a Raspberry Pi
Resources
License
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published