@@ -11,3 +11,4 @@ panic = "abort" | |||||
panic = "abort" | panic = "abort" | ||||
[dependencies] | [dependencies] | ||||
@@ -1,21 +0,0 @@ | |||||
// AArch32 mode | |||||
.section ".text.boot" | |||||
.globl _start | |||||
.org 0x8000 | |||||
_start: | |||||
mov sp, #0x8000 | |||||
ldr r4, =__bss_start | |||||
ldr r9, =__bss_end | |||||
mov r5, #0 | |||||
mov r6, #0 | |||||
mov r7, #0 | |||||
mov r8, #0 | |||||
b 2f | |||||
1: stmia r4!, {r4-r8} | |||||
2: cmp r4, r9 | |||||
blo 1b | |||||
ldr r4, =kernel_main | |||||
blx r3 | |||||
halt: wfe | |||||
b halt | |||||
@@ -1,7 +1,14 @@ | |||||
# build the OS | |||||
build-os: | build-os: | ||||
arm-none-eabi-gcc -mcpu=cortex-a7 -fpic -ffreestanding -c asm/boot-2.s -o build/boot.o | |||||
cargo xbuild --release --target armv7r-none-eabihf | |||||
arm-none-eabi-gcc -T linker.ld -o build/grove.img -ffreestanding -O2 -nostdlib build/boot.o target/target/release/libgrove.rlib | |||||
rm build/* | |||||
arm-none-eabi-gcc -mcpu=cortex-a7 -fpic -ffreestanding -c asm/boot.s -o build/boot.o | |||||
cargo xbuild --target armv7a-none-eabi | |||||
arm-none-eabi-gcc -T linker.ld -o build/grove.img -ffreestanding -O2 -nostdlib build/boot.o target/armv7a-none-eabi/debug/libgrove.rlib | |||||
run-os: build-os | |||||
qemu-system-arm -M raspi2 -kernel build/grove.img -serial stdio | |||||
# build the OS and run it on QEMU | |||||
run: build-os | |||||
qemu-system-arm -M raspi2 -kernel build/grove.img -serial stdio | |||||
# build just the rust binary | |||||
build: | |||||
cargo xbuild --target armv7a-none-eabi |
@@ -1,51 +1,59 @@ | |||||
#![no_std] | #![no_std] | ||||
#![feature(asm)] | |||||
use core::panic::PanicInfo; | |||||
use core::ptr::{read_volatile, write_volatile}; | |||||
const UART_DR: u32 = 0x3f20_1000; | |||||
const UART_FR: u32 = 0x3f20_1018; | |||||
fn mmio_write(reg: u32, val: u32) { | |||||
unsafe { write_volatile(reg as *mut u32, val) } | |||||
} | |||||
mod mem; | |||||
fn mmio_read(reg: u32) -> u32 { | |||||
unsafe { read_volatile(reg as *const u32) } | |||||
} | |||||
use core::panic::PanicInfo; | |||||
fn transmit_fifo_full() -> bool { | |||||
mmio_read(UART_FR) & (1 << 5) > 0 | |||||
/// represents the board type | |||||
#[derive(PartialEq, Eq)] | |||||
pub enum BoardType { | |||||
PiZeroOne, | |||||
PiTwo, | |||||
PiThree, | |||||
PiFour, | |||||
Unknown, | |||||
} | } | ||||
fn receive_fifo_empty() -> bool { | |||||
mmio_read(UART_FR) & (1 << 4) > 0 | |||||
} | |||||
impl BoardType { | |||||
/// detect the type of Raspberry Pi board | |||||
pub fn detect() -> Self { | |||||
let mut reg_data: u32; | |||||
fn writec(c: u8) { | |||||
while transmit_fifo_full() {} | |||||
mmio_write(UART_DR, c as u32); | |||||
} | |||||
unsafe { | |||||
asm!("mrc p15, 0, {}, c0, c0, 0", out(reg) reg_data); | |||||
} | |||||
fn getc() -> u8 { | |||||
while receive_fifo_empty() {} | |||||
mmio_read(UART_DR) as u8 | |||||
} | |||||
match reg_data >> 4 & 0xFFF { | |||||
0xB76 => BoardType::PiZeroOne, | |||||
0xC07 => BoardType::PiTwo, | |||||
0xD03 => BoardType::PiThree, | |||||
0xD08 => BoardType::PiFour, | |||||
_ => BoardType::Unknown, | |||||
} | |||||
} | |||||
fn write(msg: &str) { | |||||
for c in msg.bytes() { | |||||
writec(c); | |||||
/// return the MMIO base address | |||||
pub fn mmio_base_addr(self) -> *const u32 { | |||||
match self { | |||||
BoardType::PiZeroOne | BoardType::Unknown => 0x2000_0000 as *const u32, | |||||
BoardType::PiTwo | BoardType::PiThree => 0x3F00_0000 as *const u32, | |||||
BoardType::PiFour => 0xFE00_0000 as *const u32, | |||||
} | |||||
} | } | ||||
} | } | ||||
#[no_mangle] | #[no_mangle] | ||||
pub extern "C" fn kernel_main() { | pub extern "C" fn kernel_main() { | ||||
write("hello rust raspberry pi kernel"); | |||||
loop { | |||||
writec(getc()) | |||||
} | |||||
let board_type = BoardType::detect(); | |||||
let mem = mem::MemoryMappedIo::init(board_type); | |||||
mem.write_str("hello grove kernel <3"); | |||||
loop {} | |||||
} | } | ||||
/// these functions are here to make the compiler/linker happy :) | |||||
#[no_mangle] | #[no_mangle] | ||||
pub extern "C" fn __aeabi_unwind_cpp_pr0() {} | pub extern "C" fn __aeabi_unwind_cpp_pr0() {} | ||||
@@ -0,0 +1,80 @@ | |||||
pub struct MemoryMappedIo { | |||||
base_addr: *const u32, | |||||
} | |||||
impl MemoryMappedIo { | |||||
pub fn init(board_type: crate::BoardType) -> Self { | |||||
let mem = MemoryMappedIo { base_addr: board_type.mmio_base_addr() }; | |||||
mem.uart_init(); | |||||
mem | |||||
} | |||||
fn uart_init(&self) {} | |||||
// receive fifo empty | |||||
fn recv_fifo_empty(&self) -> bool { | |||||
self.read_word(PeripheralAddress::UartFr) & (1 << 5) > 0 | |||||
} | |||||
// transmit fifo full | |||||
fn tran_fifo_full(&self) -> bool { | |||||
self.read_word(PeripheralAddress::UartFr) & (1 << 4) > 0 | |||||
} | |||||
pub fn write_str(&self, s: &str) { | |||||
s.bytes().for_each(|byte| self.write_byte(byte)) | |||||
} | |||||
pub fn write_byte(&self, byte: u8) { | |||||
while self.tran_fifo_full() {} | |||||
self.write_word(PeripheralAddress::UartDr, byte as u32); | |||||
} | |||||
pub fn get_byte(&self) -> u8 { | |||||
while self.recv_fifo_empty() {} | |||||
self.read_word(PeripheralAddress::UartDr) as u8 | |||||
} | |||||
// write a word to the memory mapped IO | |||||
pub fn write_word(&self, peripheral_addr: PeripheralAddress, data: u32) { | |||||
unsafe { | |||||
let addr = self.base_addr.offset(peripheral_addr as isize) as *mut u32; | |||||
addr.write_volatile(data); | |||||
} | |||||
} | |||||
// read a word from memory mapped IO | |||||
pub fn read_word(&self, peripheral_addr: PeripheralAddress) -> u32 { | |||||
unsafe { | |||||
let addr = self.base_addr.offset(peripheral_addr as isize) as *mut u32; | |||||
addr.read_volatile() | |||||
} | |||||
} | |||||
} | |||||
/// represents the offset from the base address | |||||
#[allow(dead_code)] | |||||
#[repr(isize)] | |||||
pub enum PeripheralAddress { | |||||
Gpiobase = 0x0020_0000, | |||||
Gppud = 0x0020_0094, | |||||
Gppudclk0 = 0x0020_0098, | |||||
UartDr = 0x0020_1000, | |||||
UartRsrecr = 0x0020_1004, | |||||
UartFr = 0x0020_1018, | |||||
UartIlpr = 0x0020_1020, | |||||
UartIbrd = 0x0020_1024, | |||||
UartFbrd = 0x0020_1028, | |||||
UartLcrh = 0x0020_102C, | |||||
UartCr = 0x0020_1030, | |||||
UartIfls = 0x0020_1034, | |||||
UartImsc = 0x0020_1038, | |||||
Uartris = 0x0020_103C, | |||||
UartMis = 0x0020_1040, | |||||
UartIcr = 0x0020_1044, | |||||
UartDmacr = 0x0020_1048, | |||||
UartItcr = 0x0020_1080, | |||||
UartItip = 0x0020_1084, | |||||
UartItop = 0x0020_1088, | |||||
UartTdr = 0x0020_108C, | |||||
} |