AlexandreZani
Posts: 2
Joined: Tue Jul 03, 2012 6:35 pm

Programming the RPi on the bare metal

Tue Jul 03, 2012 6:38 pm

Hello all,

I'm wondering if anybody has docs on writing for the RPi on the bare metal. I'm thinking a hobby OS could be a fun projects, but I would love to see what needs to happen to get the thing to boot.

User avatar
DexOS
Posts: 876
Joined: Wed May 16, 2012 6:32 pm
Contact: Website

Re: Programming the RPi on the bare metal

Tue Jul 03, 2012 7:42 pm

The very basic you will need, is to format the SD card to fat32, add the files
"bootcode.bin" "loader.bin" "start.elf" and "config.txt"
and your code would be a flat bin with a .img extension called kernel.img
With a org of 0x8000
Like this fasmarm example that does nothing, but loops.

Code: Select all

format binary as 'img'
org	0x8000
use32
; -------------------------------------------------------
; Start
; -------------------------------------------------------
Start:
   b   Start
Thats it, you can also use offset 0, but you will need to set opions in the config.txt.
Batteries not included, Some assembly required.

AlexandreZani
Posts: 2
Joined: Tue Jul 03, 2012 6:35 pm

Re: Programming the RPi on the bare metal

Tue Jul 03, 2012 8:44 pm

DexOS wrote:The very basic you will need, is to format the SD card to fat32, add the files
"bootcode.bin" "loader.bin" "start.elf" and "config.txt"
and your code would be a flat bin with a .img extension called kernel.img
What are bootcode.bin, loader.bin, start.elf and config.txt ? (Where are they documented?)

User avatar
DexOS
Posts: 876
Joined: Wed May 16, 2012 6:32 pm
Contact: Website

Re: Programming the RPi on the bare metal

Wed Jul 04, 2012 2:06 pm

AlexandreZani wrote:
DexOS wrote:The very basic you will need, is to format the SD card to fat32, add the files
"bootcode.bin" "loader.bin" "start.elf" and "config.txt"
and your code would be a flat bin with a .img extension called kernel.img
What are bootcode.bin, loader.bin, start.elf and config.txt ? (Where are they documented?)
http://elinux.org/RPi_config.txt

https://github.com/raspberrypi/firmware ... a5f3f/boot
Batteries not included, Some assembly required.

User avatar
AndrewS
Posts: 3625
Joined: Sun Apr 22, 2012 4:50 pm
Location: Cambridge, UK
Contact: Website

Re: Programming the RPi on the bare metal

Wed Jul 04, 2012 2:35 pm

AlexandreZani wrote:What are bootcode.bin, loader.bin, start.elf and config.txt ? (Where are they documented?)
http://www.raspberrypi.org/phpBB3/viewt ... =26&t=6365 and make sure you also read the other thread I linked to in the last post of that one.

mszegedy
Posts: 1
Joined: Thu Jul 05, 2012 4:52 am

Re: Programming the RPi on the bare metal

Thu Jul 05, 2012 5:01 am

The best tutorial I have ever seen on writing your own (Linux) operating system is this. It's seriously amazing how well it goes through the stuff. I highly recommend it. This is the optimum combination that I have found to automate things: Raspberry Pi + LFS.

User avatar
AndrewS
Posts: 3625
Joined: Sun Apr 22, 2012 4:50 pm
Location: Cambridge, UK
Contact: Website

Re: Programming the RPi on the bare metal

Thu Jul 05, 2012 10:28 am

Just to be pedantic: LinuxFromScratch is another (highly customisable) Linux Distribution, not an entirely new 'bare metal' OS that the OP was asking for ;)

aaa801
Posts: 428
Joined: Mon Jun 04, 2012 9:06 pm
Location: Berkshire

Re: Programming the RPi on the bare metal

Thu Jul 05, 2012 3:52 pm

My friend started working on this a few days ago
https://github.com/arianvp/SummerOS

tufty
Posts: 1456
Joined: Sun Sep 11, 2011 2:32 pm

Re: Programming the RPi on the bare metal

Thu Jul 05, 2012 5:35 pm

It appears to be x86, though, and thus of no use to pi users.

Simon.

Also, see .sig

dwelch67
Posts: 936
Joined: Sat May 26, 2012 5:32 pm

Re: Programming the RPi on the bare metal

Thu Jul 05, 2012 8:25 pm

AlexandreZani wrote:Hello all,

I'm wondering if anybody has docs on writing for the RPi on the bare metal. I'm thinking a hobby OS could be a fun projects, but I would love to see what needs to happen to get the thing to boot.
http://github.com/dwelch67/raspberrypi

pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: Programming the RPi on the bare metal

Thu Jul 05, 2012 11:00 pm

Hi - DexOS said:
The very basic you will need, is to format the SD card to fat32, add the files
"bootcode.bin" "loader.bin" "start.elf" and "config.txt"
and your code would be a flat bin with a .img extension called kernel.img
With a org of 0x8000
That is very informative and has removed alot of my fear about going bare metal...

could anyone explain what an 'org of 0x8000' is please?

I am hoping to compile my binary from C++ with inline ASM to send data to the GPIO pins or by using the WiringPi C class.
Ostendo ignarus addo scientia.

dwelch67
Posts: 936
Joined: Sat May 26, 2012 5:32 pm

Re: Programming the RPi on the bare metal

Fri Jul 06, 2012 12:25 am

pygmy_giant wrote:Hi - DexOS said:
The very basic you will need, is to format the SD card to fat32, add the files
"bootcode.bin" "loader.bin" "start.elf" and "config.txt"
and your code would be a flat bin with a .img extension called kernel.img
With a org of 0x8000
That is very informative and has removed alot of my fear about going bare metal...

could anyone explain what an 'org of 0x8000' is please?

I am hoping to compile my binary from C++ with inline ASM to send data to the GPIO pins or by using the WiringPi C class.
Well, to run bare metal there is some assembly required for the interrupt/exception vector table and a few lines of code at least to setup the stack and call C. for C++ I think there is even more of something up front. My examples show all that (for C).

Also you have to tell your toolchain in some form or fashion (depending on the tools) the base address to link the code. Sometimes on some architectures you can get away with being mostly if not complete position independent, but that is usually not the case for everything, so you need to tell the toolchain where in the processors address space things are going to live.

When we say use an org of 0x8000 that goes back to the old school assemblers, where your "toolchain" was a single assembler and the first line of code was usually:

Code: Select all

.org 0x8000
and that is how you told your "toolchain" where in the processors address space the code/data that was to follow was going to live. (see some of my msp430 assembly examples where I do that kind of thing). The gnu tools, be it assembler, C, C++, ADA, fortran, whatever, you dont tell the assembler you compile everything to object files and then the linker is its own tool in the set of tools that just links and you tell it where these objects will live. All the objects are compiled with holes in them where the linker is going to fill in addresses or finishing building the machine code for instructions that are waiting for that step.

Now when you make a hello world program on your linux or windows or whatever operating system box, and you type

Code: Select all

gcc -o hello hello.c
There is a default linker script that knows what the operating system uses for its entry point address within the virtual address space where the application programs run. When you go bare metal you dont have an operating system with virtual memory layered over real memory, you have to look at the hardware and decide where you want things, for cases like this where you are booting the processor from reset you have to place the vector table as well and the bootstrap code and everything that leads up to entering your high level code.

for the raspberry pi, it is a bit of a strange case, you have this other processor on board (gpu) that is what actually boots up first on the chip and it copies the arm program from the sd card to ram, and you can ask the gpu to put that arm code almost wherever you want in memory, and that address is not where the vector table is necessarily, and you only get a single binary image of one chunk of memory you dont get to have an elf or coff or intel hex or srecord where you can put some stuff here and some stuff there. My personal choice, for now, is to go with whatever the default is, whatever they build the linux kernel code for, basically the address/method the masses use, the folks that dont know what is going on it just boots linux. The controls they have provided allow you to muck with that, you can have it start at address 0x0000 instead of 0x8000 and some if maybe many of the bare metal folks are doing that, perhaps because that is where they mainstream loader used to be, at some point not long ago the gpu boot code changed from 0x0000 to 0x8000. so when you look at my examples, for now, they are linked for address 0x8000 and assume that if any exception table needs to be built it is a special case.

Hope that helps...

Now that I have typed all of that I just thought of something that I should try that will maybe make my images/examples not care...I still would have to type all that to answer your question...

David

xernobyl
Posts: 26
Joined: Tue Oct 25, 2011 2:03 pm

Re: Programming the RPi on the bare metal

Fri Jul 06, 2012 1:00 am

Similar to this, what would be the minimum to have OpenGL support?

User avatar
mahjongg
Forum Moderator
Forum Moderator
Posts: 10710
Joined: Sun Mar 11, 2012 12:19 am
Location: South Holland, The Netherlands

Re: Programming the RPi on the bare metal

Fri Jul 06, 2012 1:23 am

xernobyl wrote:Similar to this, what would be the minimum to have OpenGL support?
That wouldn't be "bare metal programming" wouldn't it. Bare metal programming involves directly writing words (pixels) to a memory area, dedicated as a frame buffer. Or better yet, to a text console.

dwelch67
Posts: 936
Joined: Sat May 26, 2012 5:32 pm

Re: Programming the RPi on the bare metal

Fri Jul 06, 2012 5:23 am

mahjongg wrote:
xernobyl wrote:Similar to this, what would be the minimum to have OpenGL support?
That wouldn't be "bare metal programming" wouldn't it. Bare metal programming involves directly writing words (pixels) to a memory area, dedicated as a frame buffer. Or better yet, to a text console.
Bare metal is what the hardware provides. if the hardware provides texture mapping on surfaces then that is bare metal. Another way to think of it is bare metal means without an operating system, you are not making operating system calls to do stuff. You are sitting on the hardware not on the OS. This one is odd in that we have this closed source GPU to go through, can still do that without the operating system.

It is similar to the word embedded which has a very wide definition and most of the uses are correct.

tufty
Posts: 1456
Joined: Sun Sep 11, 2011 2:32 pm

Re: Programming the RPi on the bare metal

Fri Jul 06, 2012 7:20 am

xernobyl wrote:Similar to this, what would be the minimum to have OpenGL support?
To get OpenGL support would take a bit of work. We'll ignore the possibility of reverse-engineering the Broadcom binaries to produce our own version of OpenGL, and stick with the option of using the Broadcom Binaries "as is".

So, with the appropriate toolset, we could probably take the libraries and link them statically into our own "bare metal" kernel. That avoids having to provide an elf dynamic loading mechanism (probably best, because for the moment, SD card access is a bit "opaque".

Aside from that, we'd need to know what the libraries themselves depend on. That's a bit tricky, but probably do-able - the final result is that we have to link in or otherwise provide every symbol that the libraries we're linking need (and on the face of it, it seems not all the libraries needed are provided with static versions). A bit tricksy, like I said.

After that, you'd need to provide something that looks close enough to the Linux kernel interface so that the code can talk to the GPU.

This is, quite obviously, "a piece of cake"!

Of course, your kernel is liable to get a bit fat with all that. My own dev kernel (which includes multitasking, serial port access, framebuffer access and a couple of other bits and pieces, along with an onboard scheme interpreter), comes in at 11k, total. Just libGLESv2_static.a comes in at over 104k, libkhrn_static.a is over 400k, and so on.

Simon

dwelch67
Posts: 936
Joined: Sat May 26, 2012 5:32 pm

Re: Programming the RPi on the bare metal

Fri Jul 06, 2012 2:46 pm

pygmy_giant wrote:Hi - DexOS said:
The very basic you will need, is to format the SD card to fat32, add the files
"bootcode.bin" "loader.bin" "start.elf" and "config.txt"
and your code would be a flat bin with a .img extension called kernel.img
With a org of 0x8000
That is very informative and has removed alot of my fear about going bare metal...

could anyone explain what an 'org of 0x8000' is please?

I am hoping to compile my binary from C++ with inline ASM to send data to the GPIO pins or by using the WiringPi C class.
http://github.com/dwelch67/raspberrypi zero_start directory

Using a simple copy loop on arm entry, and the assumption that you are being loaded far enough away (0x100 bytes in this case) from zero, a solution like this allows you to not care where the gpu places the kernel.img in ram. Granted if it is a large program this copy will take a while.


.globl _start
_start:
b reset
b hang
b hang
b hang

b hang
b hang
b hang
b hang

text_size_x: .word text_size
soffset: .word reset - _start + 8

reset:
mov r0,pc
ldr r1,soffset
sub r0,r1
cmp r0,#0
beq skip_copy
mov r1,#0;
ldr r2,text_size_x
add r2,r2,#0xFF
add r2,r2,#15
mov r2,r2,lsr #4
copy_loop:
ldmia r0!,{r4,r5,r6,r7}
stmia r1!,{r4,r5,r6,r7}
subs r2,r2,#1
bne copy_loop
mov r0,#0
bx r0

skip_copy:

mov sp,#0x8000
mov r0,pc
bl notmain
hang: b hang


for the above to work with gnu tools you need something in the linker script, first build for address zero, second put a variable in the script that the asm uses to know how big things are. I dont use/care about the pre-main content of .bss and .data, but many programmers do so I leave it as an exercise to the reader to modify this for that case. To add the size and variable was a single google search, first hit showed examples of what I was looking for. YMMV.

MEMORY
{
ram : ORIGIN = 0x0000, LENGTH = 0x1000
}

SECTIONS
{
.text : { *(.text*) } > ram
text_size = SIZEOF(.text);
.bss : { *(.bss*) } > ram

}

User avatar
DexOS
Posts: 876
Joined: Wed May 16, 2012 6:32 pm
Contact: Website

Re: Programming the RPi on the bare metal

Fri Jul 06, 2012 4:51 pm

pygmy_giant wrote:Hi - DexOS said:
The very basic you will need, is to format the SD card to fat32, add the files
"bootcode.bin" "loader.bin" "start.elf" and "config.txt"
and your code would be a flat bin with a .img extension called kernel.img
With a org of 0x8000
That is very informative and has removed alot of my fear about going bare metal...

could anyone explain what an 'org of 0x8000' is please?

I am hoping to compile my binary from C++ with inline ASM to send data to the GPIO pins or by using the WiringPi C class.
Sure, in this case its where the kernel.img is to be loaded to in memory.
Heres a simple asm example (for x86, not arm)
For example if you write this code:

Code: Select all

mov eax, var1
and and lets say the address of var1 is 10h (16 in dec) from start of kernel.img
without ORG 100h (could just as easy be 0x8000) directive assembler see it as:

Code: Select all

mov eax, 10h
now the reg eax = 10h
This is fine as long as the kernel.img is loaded to 0
But if the kernel.img was loaded to 100h, then the above code would no longer point to var1, but to a address below the kernel.img.
however with ORG 100h directive assembler automatically updates the address too:

Code: Select all

mov eax, 10h+100h
now the reg eax = 110h

Now i can only advize from a assembly point of view, others will be better from HL point of view.
Hope this helps
Batteries not included, Some assembly required.

pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: Programming the RPi on the bare metal

Fri Jul 06, 2012 5:07 pm

Wow - lots to digest - feeling a bit dizzy - thanks.
Ostendo ignarus addo scientia.

tufty
Posts: 1456
Joined: Sun Sep 11, 2011 2:32 pm

Re: Programming the RPi on the bare metal

Fri Jul 06, 2012 7:53 pm

pygmy_giant wrote:Wow - lots to digest - feeling a bit dizzy - thanks.
Once you've got used to the idea that you're gonna have to do a little bit of assembler, and that you have to explicitly place at least a part of your code in memory as opposed to simply letting the linker deal with it, bare metal programming is no harder than any other type.

By "a little bit of assembler", I really do mean a little bit. You need to produce an interrupt vector table (that's a static table of data, 32 bytes, or 64 if you want to be able to patch in new interrupt handlers later). You need a reset handler, mine is 292 bytes, and you need a couple of interrupt handlers (mine include the handling for task swapping when multitasking and come to 362 bytes total). Really, it's tiny amounts of code. The rest you can do in C.

Balau has done some decent stuff on getting started with bare metal programming on ARM : http://balau82.wordpress.com/2010/02/14 ... m-for-arm/ is a decent starting point, and I've explained a lot of what I'm doing on my blog (see .sig).

Oh, and of course, Dave's stuff that he linked earlier.

Go for it. It's fun.

Simon
Last edited by tufty on Fri Jul 06, 2012 8:09 pm, edited 1 time in total.

pygmy_giant
Posts: 1562
Joined: Sun Mar 04, 2012 12:49 am

Re: Programming the RPi on the bare metal

Fri Jul 06, 2012 7:58 pm

Well... if it is realy 'only' just a little bit... :)
Ostendo ignarus addo scientia.

User avatar
Cycl0ne
Posts: 102
Joined: Mon Jun 25, 2012 8:03 am

Re: Programming the RPi on the bare metal

Sat Jul 07, 2012 4:55 am

I did a lot in C and only a really small part in ASM (setting up the Stacks for all the Interrupts and a small "handler" which calls the C code on exceptions).

Here is my C Code i use for the branch table:

Code: Select all

/** LDR instruction's code */
#define LDR_OPCODE           0xe59ff000
/** Number of exception vectors. */
#define EXC_VECTORS          8
/** Size of memory block occupied by exception vectors. */
#define EXC_VECTORS_SIZE     (EXC_VECTORS * 4)

#define EXC_BASE_ADDRESS  0x0
/* Exception Vectors */
#define EXC_RESET_VEC           (EXC_BASE_ADDRESS + 0x0)
#define EXC_UNDEF_INSTR_VEC     (EXC_BASE_ADDRESS + 0x4)
#define EXC_SWI_VEC             (EXC_BASE_ADDRESS + 0x8)
#define EXC_PREFETCH_ABORT_VEC  (EXC_BASE_ADDRESS + 0xc)
#define EXC_DATA_ABORT_VEC      (EXC_BASE_ADDRESS + 0x10)
#define EXC_IRQ_VEC             (EXC_BASE_ADDRESS + 0x18)
#define EXC_FIQ_VEC             (EXC_BASE_ADDRESS + 0x1c)

/* Exception numbers */
#define EXC_RESET           0
#define EXC_UNDEF_INSTR     1
#define EXC_SWI             2
#define EXC_PREFETCH_ABORT  3
#define EXC_DATA_ABORT      4
#define EXC_IRQ             5
#define EXC_FIQ             6

static void install_handler(unsigned handler_addr, unsigned *vector)
{
	/* relative address (related to exc. vector) of the word
	 * where handler's address is stored
	*/
	volatile UINT32 handler_address_ptr = EXC_VECTORS_SIZE - PREFETCH_OFFSET;
	
	/* make it LDR instruction and store at exception vector */
	*vector = handler_address_ptr | LDR_OPCODE;

	/* store handler's address */
	*(vector + EXC_VECTORS) = handler_addr;
}

void install_exception_handlers(void)
{
	install_handler((unsigned) reset_exception_entry, (unsigned *) EXC_RESET_VEC);
}

exception.asm

reset_exception_entry:
	SAVE_REGISTERS_TO_STACK
	mov r0, #0
	mov r1, r13
	bl _IRQServer
	LOAD_REGISTERS_FROM_STACK
So asm doesnt need to frighten you. you can easily do alot in c. Next, the community here is great, I learned a lot from tufty and dwelchs code for a start. And to be honest. In the beginning this arm cpu is really annoying when you come from a cisc cpu, but if you get the "spirit" of arm, why something is done the arm way in cpu. you will be going easy.

User avatar
DexOS
Posts: 876
Joined: Wed May 16, 2012 6:32 pm
Contact: Website

Re: Programming the RPi on the bare metal

Sat Jul 07, 2012 1:05 pm

Theres nothing hard about assembly, its the simplest programming language theres is.
Its simple because you control everthing, once your past the, this looks so complected part, you will find it easy.
The part that is much harder and makes coding something in ASM take longer, is you need to code everything yourself, theres no lib you can just include and get the work done for you.
Theres no just cross compiling to port it, but there again you get a much better OS or app if you rewrite it for that processor.
Example R-PI interrupts are not the same as a lot of other arm devices.

So in short ASM is like a scalpel, yes you can cut your fingers off if your not careful, but you can also save lives, HL are like plastic knives, yes very safe, but limited in uses.
Batteries not included, Some assembly required.

User avatar
mahjongg
Forum Moderator
Forum Moderator
Posts: 10710
Joined: Sun Mar 11, 2012 12:19 am
Location: South Holland, The Netherlands

Re: Programming the RPi on the bare metal

Sat Jul 07, 2012 6:43 pm

dwelch67 wrote:
mahjongg wrote:
xernobyl wrote:Similar to this, what would be the minimum to have OpenGL support?
That wouldn't be "bare metal programming" wouldn't it. Bare metal programming involves directly writing words (pixels) to a memory area, dedicated as a frame buffer. Or better yet, to a text console.
Bare metal is what the hardware provides. if the hardware provides texture mapping on surfaces then that is bare metal. Another way to think of it is bare metal means without an operating system, you are not making operating system calls to do stuff. You are sitting on the hardware not on the OS. This one is odd in that we have this closed source GPU to go through, can still do that without the operating system.

It is similar to the word embedded which has a very wide definition and most of the uses are correct.
Well, in that sense you cannot do "bare metal programming" on the GPU, as its "bare metal" (its registers) are not documented (Do note that even if they were documented, you would need several decades of your live do do "bare metal programming" on it, even provided that you would be capable of doing so).
So the GPU is out for "bare metal programming". Obviously you could control the GPU through a driver (OpenGL ES) but then you are not doing "bare metal" programming anymore, as bare mental means you are directly controlling the physical interfaces of the silicon (the "metal"), of the chip.

That leaves the other "physical" interface to "the silicon", for display output, and that is that you can write to memory locations that the video hardware uses to display stuff (A.K.A. a frame buffer).

tufty
Posts: 1456
Joined: Sun Sep 11, 2011 2:32 pm

Re: Programming the RPi on the bare metal

Sat Jul 07, 2012 8:04 pm

DexOS wrote:So in short ASM is like a scalpel, yes you can cut your fingers off if your not careful, but you can also save lives, HL are like plastic knives, yes very safe, but limited in uses.
That's possibly the most utterly wrong statement I've come across all week. You win a prize.

;)

Return to “Bare metal, Assembly language”

Who is online

Users browsing this forum: No registered users and 4 guests