Raspberry Pi Bare Bones: Difference between revisions

Fixed discrepancy between rpi1, 2 & 3, fixed typos, made code more sane and altered info.
[unchecked revision][unchecked revision]
(Fixed discrepancy between rpi1, 2 & 3, fixed typos, made code more sane and altered info.)
Line 1:
{{Rating|1}}{{Template:Kernel designs}}
 
This is a tutorial on operating systems 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) in every way other than the memory-mapped location of serial I/O. This will serve as an example of how to create a minimal system, but not as an example of how to properly structure your project.
 
<big><b>WAIT! Have you read [[Getting Started]], [[Beginner Mistakes]], and some of the related [[:Category:OS theory|OS theory]]?</b></big>
Line 88:
=== Freestanding and Hosted Environments ===
 
If you have done C or C++ programming in user-space, you have used a so-called Hosted Environment. Hosted means that there is a C standard library and other useful runtime features. Alternatively, there is the Freestanding version, which is what we are using here. Freestanding means that there is no C standard library, only what we provide ourselves. However, some header files are actually not part of the C standard library, but rather the compiler. These remain available even in freestanding C source code. In this case we use <stdbool.h> to get the bool datatype, <stddef.h> to get size_t and& NULL, and <stdint.h> to get the intx_t and uintx_t datatypes which are invaluable for operating systems development, where you need to make sure that the variable is of an exact size (if we used a short instead of uint16_t and the size of short changed, our VGA driver here would break!). Additionally you can access the <float.h>, <iso646.h>, <limits.h>, and <stdarg.h> headers, as they are also freestanding. GCC actually ships a few more headers, but these are special purpose.
 
=== Writing a kernel in C ===
Line 95:
 
<source lang="cpp">
#if !defined(__cplusplus)
#include <stdbool.h>
#endif
#include <stddef.h>
#include <stdint.h>
 
// Memory-Mapped I/O output
static inline void mmio_write(uint32_t reg, uint32_t data)
{
*(volatile uint32_t *)reg = data;
}
 
// Memory-Mapped I/O input
static inline uint32_t mmio_read(uint32_t reg)
{
return *(volatile uint32_t *)reg;
}
 
/*/ Loop <delay> times in a way that the compiler won't optimize away. */
static inline void delay(int32_t count)
{
asm volatile("__delay_%=: subs %[count], %[count], #1; bne __delay_%=\n"
: "=r"(count): [count]"0"(count) : "cc");
}
 
size_t strlen(const char* str)
{
size_t ret = 0;
while ( str[ret] != 0 )
ret++;
return ret;
}
 
Line 129 ⟶ 120:
{
// The GPIO registers base address.
GPIO_BASE = 0x202000000x3F200000, // 0x3F200000 for raspi2 and& 3, 0x20200000 for raspi3raspi1
 
// The offsets for reach register.
Line 140 ⟶ 131:
 
// The base address for UART.
UART0_BASE = 0x202010000x3F201000, // 0x3F201000 for raspiraspi2 2& and3, 0x20201000 for raspi3raspi1
 
// The offsets for reach register for the UART.
Line 189 ⟶ 180:
 
// Divider = 3000000 / (16 * 115200) = 1.627 = ~1.
// Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40.
mmio_write(UART0_IBRD, 1);
// Fractional part register = (.627 * 64) + 0.5 = 40.6 = ~40.
mmio_write(UART0_FBRD, 40);
 
Line 204 ⟶ 195:
}
 
void uart_putc(unsigned char bytec)
{
// Wait for UART to become ready to transmit.
while ( mmio_read(UART0_FR) & (1 << 5) ) { }
mmio_write(UART0_DR, bytec);
}
 
unsigned char uart_getc()
{
// Wait for UART to have recievedreceived something.
while ( mmio_read(UART0_FR) & (1 << 4) ) { }
return mmio_read(UART0_DR);
}
 
void uart_write(const unsigned char* buffer, size_t size)
{
for ( size_t i = 0; i < size; i++ )
uart_putc(buffer[i]);
}
 
void uart_puts(const char* str)
{
for ( size_t i = 0; str[i] <!= size'\0'; i ++ )
uart_write((const unsigned char*) str, strlen(str));
uart_putc(buffer(unsigned char)str[i]);
}
 
Line 234 ⟶ 220:
void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags)
{
// Declare as unused
(void) r0;
(void) r1;
Line 241 ⟶ 228:
uart_puts("Hello, kernel World!\r\n");
 
while ( true 1)
uart_putc(uart_getc());
}
Line 389 ⟶ 376:
 
<source lang=text>
$YOURINSTALLLOCATION/bin/qemu-system-arm -kernel kernel.elf -m 256 -M raspi2 -serial stdio -kernel kernel.elf
</source>
 
35

edits