Skip to content

Commit

Permalink
0.1
Browse files Browse the repository at this point in the history
  • Loading branch information
markfirmware committed Sep 20, 2019
1 parent 14e2c1c commit baa7cbd
Show file tree
Hide file tree
Showing 19 changed files with 1,092 additions and 0 deletions.
46 changes: 46 additions & 0 deletions .github/workflows/main.yml
@@ -0,0 +1,46 @@
name: CI

on: [push]

jobs:
build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v1
- name: install software
run: |
sudo apt-get -qq install llvm
ls -lt /usr/bin/llvm-objcopy*
wget --quiet --output-document=- https://github.com/github/hub/releases/download/v2.12.3/hub-linux-amd64-2.12.3.tgz | tar zx
mv hub-linux-* hub
./hub/bin/hub --version
ZIG=$(wget --quiet --output-document=- https://ziglang.org/download/index.json | jq --raw-output '.master."x86_64-linux".tarball')
wget --quiet --output-document=- $ZIG | tar Jx
mv zig-linux-x86_64-* zig
echo zig version $(./zig/zig version)
- name: build
run: |
REPO=$(basename $GITHUB_REPOSITORY)
./zig/zig build -Darmv6
cp -a $REPO-armv6.img boot/
./zig/zig build -Darmv7
cp -a $REPO-armv7.img boot/
- name: release draft
env:
GITHUB_USER: $GITHUB_ACTOR
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
REPO=$(basename $GITHUB_REPOSITORY)
RELEASE_TAG=$(grep '^const release_tag =' src/main.zig | sed 's/";//' | sed 's/^.*"//')
RELEASE_ASSET=$REPO-$RELEASE_TAG.zip
pushd boot
echo $RELEASE_TAG > RELEASE.md
echo >> RELEASE.md
cat ../release-message.md >> RELEASE.md
zip -r $RELEASE_ASSET .
../hub/bin/hub release create --draft --prerelease --file RELEASE.md --attach $RELEASE_ASSET $RELEASE_TAG
popd
6 changes: 6 additions & 0 deletions .gitignore
@@ -0,0 +1,6 @@
*.bin
*.dat
*.elf
*.img
*.zip
zig-cache/
5 changes: 5 additions & 0 deletions README.md
@@ -0,0 +1,5 @@
zig logo is displayed

Successfully tested on rpi3b, rpi3b+

Not yet working on armv6 raspberry pi models
Binary file added assets/zig-logo.bmp
Binary file not shown.
33 changes: 33 additions & 0 deletions assets/zig-logo.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added boot/bootcode.bin
Binary file not shown.
19 changes: 19 additions & 0 deletions boot/config.txt
@@ -0,0 +1,19 @@
# https://www.raspberrypi.org/documentation/configuration/config-txt/

disable_commandline_tags=1
kernel_old=1
dtparam=audio=on
disable_splash=1
boot_delay=0
cec_osd_name=Zig!

[rpi0]
kernel=zig-bare-metal-raspberry-pi-armv6.img
[rpi1]
kernel=zig-bare-metal-raspberry-pi-armv6.img
[rpi2]
kernel=zig-bare-metal-raspberry-pi-armv7.img
[rpi3]
kernel=zig-bare-metal-raspberry-pi-armv7.img
[rpi4]
kernel=zig-bare-metal-raspberry-pi-armv7.img
Binary file added boot/fixup.dat
Binary file not shown.
Binary file added boot/start.elf
Binary file not shown.
43 changes: 43 additions & 0 deletions build.zig
@@ -0,0 +1,43 @@
const std = @import("std");
const Builder = std.build.Builder;
const builtin = @import("builtin");

pub fn build(b: *Builder) void {
const mode = b.standardReleaseOptions();
const want_armv6 = b.option(bool, "armv6", "Build armv6 instead of armv7 (armv7 is default)") orelse false;
const want_armv7 = b.option(bool, "armv7", "Build armv7 instead of armv6 (armv7 is default)") orelse false;

const exec_name = "zig-bare-metal-raspberry-pi";
const exe = b.addExecutable(exec_name, "src/main.zig");
exe.setOutputDir("zig-cache");
exe.setBuildMode(mode);

var arch: builtin.Arch = undefined;
var subarch: u32 = undefined;
var kernel_name: []const u8 = undefined;
if (want_armv6) {
arch = builtin.Arch{ .arm = builtin.Arch.Arm32.v6 };
subarch = 6;
kernel_name = exec_name ++ "-armv6.img";
} else {
arch = builtin.Arch{ .arm = builtin.Arch.Arm32.v7 };
subarch = 7;
kernel_name = exec_name ++ "-armv7.img";
}
const os = builtin.Os.freestanding;
const environ = builtin.Abi.eabihf;
exe.setTarget(arch, builtin.Os.freestanding, environ);
exe.addBuildOption(u32, "subarch", subarch);

const linker_script = "src/linker.ld";
exe.setLinkerScriptPath(linker_script);

const run_objcopy = b.addSystemCommand([_][]const u8{
"llvm-objcopy-6.0", exe.getOutputPath(),
"-O", "binary",
kernel_name,
});
run_objcopy.step.dependOn(&exe.step);

b.default_step.dependOn(&run_objcopy.step);
}
17 changes: 17 additions & 0 deletions release-message.md
@@ -0,0 +1,17 @@
# Requires:
* a raspberry pi model 3b or 3b+ with a power supply
* a computer that can write an sd card
* an sd card that you can erase - its contents will be destroyed
* an hdmi tv and an hdmi cable

# Steps:
* with the computer
* format the sd card as FAT32
* this destroys the current contents of the sd card
* download the zip file
* unzip it to the sd card
* insert the sd card into the pi
* connect the pi to the tv using the hdmi cable
* turn on the tv
* apply power to the pi
* you should see the zig logo displayed along a changing banner of colored lines
112 changes: 112 additions & 0 deletions src/arm_assembly_code.zig
@@ -0,0 +1,112 @@
pub const PERIPHERAL_BASE = if (build_options.subarch >= 7) 0x3F000000 else 0x20000000;

var already_panicking: bool = false;
pub fn panicf(comptime fmt: []const u8, args: ...) noreturn {
@setCold(true);
if (already_panicking) {
hang("\npanicked during kernel panic");
}
already_panicking = true;

serial.log("panic: " ++ fmt, args);
hang("panic completed");
}

pub fn io(offset: u32) *volatile u32 {
return @intToPtr(*volatile u32, PERIPHERAL_BASE + offset);
}

pub fn ioStruct(comptime StructType: type, offset: u32) *volatile StructType {
return @intToPtr(*volatile StructType, PERIPHERAL_BASE + offset);
}

// Loop count times in a way that the compiler won't optimize away.
pub fn delay(count: usize) void {
var i: usize = 0;
while (i < count) : (i += 1) {
asm volatile("mov r0, r0");
}
}

pub fn hang(comptime format: []const u8, args: ...) noreturn {
serial.log(format, args);
while (true) {
if (build_options.subarch >= 7) {
v7.wfe();
}
}
}

pub const v7 = struct {
pub inline fn mpidr() u32 {
var word = asm("mrc p15, 0, %[word], c0, c0, 5"
: [word] "=r" (-> usize));
return word;
}

pub inline fn wfe() void {
asm volatile("wfe");
}
};

pub fn sp() u32 {
var word = asm("mov %[word], sp"
: [word] "=r" (-> usize));
return word;
}

pub fn cpsr() u32 {
var word = asm("mrs %[word], cpsr"
: [word] "=r" (-> usize));
return word;
}

pub fn spsr() u32 {
var word = asm("mrs %[word], spsr"
: [word] "=r" (-> usize));
return word;
}

pub fn sctlr() u32 {
var word = asm("mrc p15, 0, %[word], c1, c0, 0"
: [word] "=r" (-> usize));
return word;
}

pub fn scr() u32 {
var word = asm("mrc p15, 0, %[word], c1, c1, 0"
: [word] "=r" (-> usize));
return word;
}

pub fn dsbSt() void {
if (build_options.subarch >= 7) {
asm volatile("dsb st");
} else {
asm volatile("mcr p15, 0, r0, c7, c10, 4"
:
:
: "r0");
}
}

pub fn setVectorBaseAddressRegister(address: u32) void {
asm volatile("mcr p15, #0, %[address], cr12, cr0, 0"
:
: [address] "{r0}" (address)
);
}

// The linker will make the address of these global variables equal
// to the value we are interested in. The memory at the address
// could alias any uninitialized global variable in the kernel.
extern var __bss_start: u8;
extern var __bss_end: u8;
extern var __end_init: u8;

pub fn setBssToZero() void {
@memset((*volatile [1]u8)(&__bss_start), 0, @ptrToInt(&__bss_end) - @ptrToInt(&__bss_start));
}

const build_options = @import("build_options");
const serial = @import("serial.zig");
83 changes: 83 additions & 0 deletions src/gpio.zig
@@ -0,0 +1,83 @@
pub fn setAlt5(pin_number: u32) void {
setPinPull(pin_number, Pull.None);
setPinFunction(pin_number, GPIO_FUNCTION_ALT5);
}

pub fn initOutputPinWithPullNone(pin_number: u32) void {
setPinPull(pin_number, Pull.None);
setPinFunction(pin_number, GPIO_FUNCTION_OUT);
}

pub fn setPinOutputBool(pin_number: u32, onOrOff: bool) void {
if (onOrOff) {
pins_set.write(pin_number, 1);
} else {
pins_clear.write(pin_number, 1);
}
}

fn setPinPull(pin_number: u32, pull: Pull) void {
GPPUD.* = @enumToInt(pull);
arm.delay(150);
pins_pull.write(pin_number, 1);
arm.delay(150);
GPPUD.* = @enumToInt(Pull.None);
pins_pull.write(pin_number, 0);
}

fn setPinFunction(pin_number: u32, function: u32) void {
pins_function.write(pin_number, function);
}

pub fn ioArrayOf(base: u32, field_size: u32, length: u32) type {
var IoArray = struct {
const Self = @This();

fn write(self: Self, index: u32, value: u32) void {
const field_mask = u32(1) << @intCast(u5, field_size - 1);
rangeCheck(index, length - 1);
rangeCheck(value, field_mask);
const fields_per_word = 32 / field_size;
const register = @intToPtr(*volatile u32, base + (index / fields_per_word) * 4);
const shift = @intCast(u5, (index % fields_per_word) * field_size);
var word = register.*;
word &= ~(field_mask << shift);
word |= value << shift;
register.* = word;
}
};
return IoArray;
}

fn rangeCheck(x: u32, max: u32) void {
if (x > max) {
panicf("{} exceeds max {}", x, max);
}
}

const pins_set: ioArrayOf(GPSET0, 1, GPIO_MAX_PIN) = undefined;
const pins_clear: ioArrayOf(GPCLR0, 1, GPIO_MAX_PIN) = undefined;
const pins_pull: ioArrayOf(GPPUDCLK0, 1, GPIO_MAX_PIN) = undefined;
const pins_function: ioArrayOf(GPFSEL0, 3, GPIO_MAX_PIN) = undefined;

const GPIO_MAX_PIN = 53;

const GPFSEL0 = PERIPHERAL_BASE + 0x200000;
const GPSET0 = PERIPHERAL_BASE + 0x20001C;
const GPCLR0 = PERIPHERAL_BASE + 0x200028;
const GPPUD = arm.io(0x200094);
const GPPUDCLK0 = PERIPHERAL_BASE + 0x200098;

const Pull = enum {
None,
Down,
Up,
};

const GPIO_FUNCTION_FIELD_SIZE: u32 = 3;
const GPIO_FUNCTION_OUT: u32 = 1;
const GPIO_FUNCTION_ALT5: u32 = 2;

const arm = @import("arm_assembly_code.zig");
const panicf = arm.panicf;
const PERIPHERAL_BASE = arm.PERIPHERAL_BASE;

0 comments on commit baa7cbd

Please sign in to comment.