> Before you create your blog post, would you be willing to share some of your code so that I can learn a bit about the coding style you use and the patterns you follow?
Sure, here's the current `main.rs` of my project which shows both Rust and AArch64 assembly code:
#![no_std]
#![no_main]
mod mailbox;
mod libc;
use core::arch::asm;
#[cfg(not(test))] use core::arch::global_asm;
#[cfg(not(test))] use core::panic::PanicInfo;
use core::ptr::null_mut;
use core::sync::atomic::{Ordering, fence};
use mailbox::video::{PropertyRequest, PropertyRequestTag, PropertyResponseTag, PropertyFrameBufferPixelOrder, PropertyFrameBufferAlphaMode};
// Set up a minimum environment for Rust.
#[cfg(not(test))]
global_asm!(
".globl start",
"start:",
// Set up the stack.
"ldr fp, =dyndata_end",
"sub fp, fp, #0x8",
"mov sp, fp",
"str xzr, [sp]",
// Zero-out the BSS.
"ldr x0, =bss_start",
"mov w1, wzr",
"ldr x2, =bss_end",
"sub x2, x2, x0",
"bl memset",
// Extract the CPU affinity and spin up main.
"mrs x0, mpidr_el1",
"and x0, x0, #0xff",
"bl main",
// In the event that main returns, which is unlikely, halt the system.
"bl halt",
);
#[no_mangle]
pub extern "C" fn main(affinity: u8) -> ! {
// Halt all the cores except for the first.
if affinity != 0 {halt()}
test_frame_buffer();
halt()
}
fn test_frame_buffer() {
// Set up video output.
let response = PropertyRequest::new()
.tag(PropertyRequestTag::CreateFrameBuffer(0x10))
.tag(PropertyRequestTag::ScreenBlankStatus(false))
.tag(PropertyRequestTag::FrameBufferDimensions{width: 320, height: 200})
.tag(PropertyRequestTag::FrameBufferPixelDepth(32))
.tag(PropertyRequestTag::FrameBufferPixelOrder(PropertyFrameBufferPixelOrder::Bgr))
.tag(PropertyRequestTag::FrameBufferAlphaMode(PropertyFrameBufferAlphaMode::Normal))
.query()
.unwrap();
let mut base: *mut u32 = null_mut();
let mut size = 0usize;
// Look for the framebuffer creation response which contains its base pointer and size.
for tag in response {
if let PropertyResponseTag::CreateFrameBuffer{base: returned_base, size: returned_size} = tag {
base = returned_base as *mut u32;
size = returned_size;
break;
}
}
// A zero-sized frame buffer either means that it failed to initialize or a creation tag was not returned.
if size == 0 {halt()}
unsafe {
// Fill the buffer with a color (probably green since it's little endian and the buffer is set to ABGR).
for index in 0 .. (size / 4) {
base.add(index).write(0x00ff0000);
}
}
// Make sure that all the written data makes it to the frame buffer as quickly as possible.
fence(Ordering::Release);
}
#[cfg(not(test))]
#[panic_handler]
fn panic(_: &PanicInfo) -> ! {
halt()
}
#[no_mangle]
pub extern "C" fn halt() -> ! {
unsafe {
asm!(
"0:",
"wfi",
"b 0b",
options (nomem, preserves_flags, noreturn, nostack)
);
}
}
You might have noticed that I'm mixing camel case with snake case, but that's actually a
$1 in Rust.
I'm actually writing everything from scratch for this project, including the (so far) two standard C library functions that Rust depends on: `memcpy` and `memset`. In the end the idea is to create a voxel world like Minecraft's from bare metal, but it all depends on whether I can do everything I want with the Raspberry Pi which is very poorly documented.
As for the blog, I haven't even set up the web site for it yet. That's going to be the last thing I will do if I manage to complete this project..