Skip to content

Commit baa7cbd

Browse files
committed
0.1
1 parent 14e2c1c commit baa7cbd

19 files changed

+1092
-0
lines changed

.github/workflows/main.yml

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: CI
2+
3+
on: [push]
4+
5+
jobs:
6+
build:
7+
8+
runs-on: ubuntu-latest
9+
10+
steps:
11+
- uses: actions/checkout@v1
12+
- name: install software
13+
run: |
14+
sudo apt-get -qq install llvm
15+
ls -lt /usr/bin/llvm-objcopy*
16+
17+
wget --quiet --output-document=- https://github.com/github/hub/releases/download/v2.12.3/hub-linux-amd64-2.12.3.tgz | tar zx
18+
mv hub-linux-* hub
19+
./hub/bin/hub --version
20+
21+
ZIG=$(wget --quiet --output-document=- https://ziglang.org/download/index.json | jq --raw-output '.master."x86_64-linux".tarball')
22+
wget --quiet --output-document=- $ZIG | tar Jx
23+
mv zig-linux-x86_64-* zig
24+
echo zig version $(./zig/zig version)
25+
- name: build
26+
run: |
27+
REPO=$(basename $GITHUB_REPOSITORY)
28+
./zig/zig build -Darmv6
29+
cp -a $REPO-armv6.img boot/
30+
./zig/zig build -Darmv7
31+
cp -a $REPO-armv7.img boot/
32+
- name: release draft
33+
env:
34+
GITHUB_USER: $GITHUB_ACTOR
35+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36+
run: |
37+
REPO=$(basename $GITHUB_REPOSITORY)
38+
RELEASE_TAG=$(grep '^const release_tag =' src/main.zig | sed 's/";//' | sed 's/^.*"//')
39+
RELEASE_ASSET=$REPO-$RELEASE_TAG.zip
40+
pushd boot
41+
echo $RELEASE_TAG > RELEASE.md
42+
echo >> RELEASE.md
43+
cat ../release-message.md >> RELEASE.md
44+
zip -r $RELEASE_ASSET .
45+
../hub/bin/hub release create --draft --prerelease --file RELEASE.md --attach $RELEASE_ASSET $RELEASE_TAG
46+
popd

.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
*.bin
2+
*.dat
3+
*.elf
4+
*.img
5+
*.zip
6+
zig-cache/

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
zig logo is displayed
2+
3+
Successfully tested on rpi3b, rpi3b+
4+
5+
Not yet working on armv6 raspberry pi models

assets/zig-logo.bmp

120 KB
Binary file not shown.

assets/zig-logo.svg

+33
Loading

boot/bootcode.bin

51.1 KB
Binary file not shown.

boot/config.txt

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# https://www.raspberrypi.org/documentation/configuration/config-txt/
2+
3+
disable_commandline_tags=1
4+
kernel_old=1
5+
dtparam=audio=on
6+
disable_splash=1
7+
boot_delay=0
8+
cec_osd_name=Zig!
9+
10+
[rpi0]
11+
kernel=zig-bare-metal-raspberry-pi-armv6.img
12+
[rpi1]
13+
kernel=zig-bare-metal-raspberry-pi-armv6.img
14+
[rpi2]
15+
kernel=zig-bare-metal-raspberry-pi-armv7.img
16+
[rpi3]
17+
kernel=zig-bare-metal-raspberry-pi-armv7.img
18+
[rpi4]
19+
kernel=zig-bare-metal-raspberry-pi-armv7.img

boot/fixup.dat

6.58 KB
Binary file not shown.

boot/start.elf

2.74 MB
Binary file not shown.

build.zig

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const std = @import("std");
2+
const Builder = std.build.Builder;
3+
const builtin = @import("builtin");
4+
5+
pub fn build(b: *Builder) void {
6+
const mode = b.standardReleaseOptions();
7+
const want_armv6 = b.option(bool, "armv6", "Build armv6 instead of armv7 (armv7 is default)") orelse false;
8+
const want_armv7 = b.option(bool, "armv7", "Build armv7 instead of armv6 (armv7 is default)") orelse false;
9+
10+
const exec_name = "zig-bare-metal-raspberry-pi";
11+
const exe = b.addExecutable(exec_name, "src/main.zig");
12+
exe.setOutputDir("zig-cache");
13+
exe.setBuildMode(mode);
14+
15+
var arch: builtin.Arch = undefined;
16+
var subarch: u32 = undefined;
17+
var kernel_name: []const u8 = undefined;
18+
if (want_armv6) {
19+
arch = builtin.Arch{ .arm = builtin.Arch.Arm32.v6 };
20+
subarch = 6;
21+
kernel_name = exec_name ++ "-armv6.img";
22+
} else {
23+
arch = builtin.Arch{ .arm = builtin.Arch.Arm32.v7 };
24+
subarch = 7;
25+
kernel_name = exec_name ++ "-armv7.img";
26+
}
27+
const os = builtin.Os.freestanding;
28+
const environ = builtin.Abi.eabihf;
29+
exe.setTarget(arch, builtin.Os.freestanding, environ);
30+
exe.addBuildOption(u32, "subarch", subarch);
31+
32+
const linker_script = "src/linker.ld";
33+
exe.setLinkerScriptPath(linker_script);
34+
35+
const run_objcopy = b.addSystemCommand([_][]const u8{
36+
"llvm-objcopy-6.0", exe.getOutputPath(),
37+
"-O", "binary",
38+
kernel_name,
39+
});
40+
run_objcopy.step.dependOn(&exe.step);
41+
42+
b.default_step.dependOn(&run_objcopy.step);
43+
}

release-message.md

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Requires:
2+
* a raspberry pi model 3b or 3b+ with a power supply
3+
* a computer that can write an sd card
4+
* an sd card that you can erase - its contents will be destroyed
5+
* an hdmi tv and an hdmi cable
6+
7+
# Steps:
8+
* with the computer
9+
* format the sd card as FAT32
10+
* this destroys the current contents of the sd card
11+
* download the zip file
12+
* unzip it to the sd card
13+
* insert the sd card into the pi
14+
* connect the pi to the tv using the hdmi cable
15+
* turn on the tv
16+
* apply power to the pi
17+
* you should see the zig logo displayed along a changing banner of colored lines

src/arm_assembly_code.zig

+112
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
pub const PERIPHERAL_BASE = if (build_options.subarch >= 7) 0x3F000000 else 0x20000000;
2+
3+
var already_panicking: bool = false;
4+
pub fn panicf(comptime fmt: []const u8, args: ...) noreturn {
5+
@setCold(true);
6+
if (already_panicking) {
7+
hang("\npanicked during kernel panic");
8+
}
9+
already_panicking = true;
10+
11+
serial.log("panic: " ++ fmt, args);
12+
hang("panic completed");
13+
}
14+
15+
pub fn io(offset: u32) *volatile u32 {
16+
return @intToPtr(*volatile u32, PERIPHERAL_BASE + offset);
17+
}
18+
19+
pub fn ioStruct(comptime StructType: type, offset: u32) *volatile StructType {
20+
return @intToPtr(*volatile StructType, PERIPHERAL_BASE + offset);
21+
}
22+
23+
// Loop count times in a way that the compiler won't optimize away.
24+
pub fn delay(count: usize) void {
25+
var i: usize = 0;
26+
while (i < count) : (i += 1) {
27+
asm volatile("mov r0, r0");
28+
}
29+
}
30+
31+
pub fn hang(comptime format: []const u8, args: ...) noreturn {
32+
serial.log(format, args);
33+
while (true) {
34+
if (build_options.subarch >= 7) {
35+
v7.wfe();
36+
}
37+
}
38+
}
39+
40+
pub const v7 = struct {
41+
pub inline fn mpidr() u32 {
42+
var word = asm("mrc p15, 0, %[word], c0, c0, 5"
43+
: [word] "=r" (-> usize));
44+
return word;
45+
}
46+
47+
pub inline fn wfe() void {
48+
asm volatile("wfe");
49+
}
50+
};
51+
52+
pub fn sp() u32 {
53+
var word = asm("mov %[word], sp"
54+
: [word] "=r" (-> usize));
55+
return word;
56+
}
57+
58+
pub fn cpsr() u32 {
59+
var word = asm("mrs %[word], cpsr"
60+
: [word] "=r" (-> usize));
61+
return word;
62+
}
63+
64+
pub fn spsr() u32 {
65+
var word = asm("mrs %[word], spsr"
66+
: [word] "=r" (-> usize));
67+
return word;
68+
}
69+
70+
pub fn sctlr() u32 {
71+
var word = asm("mrc p15, 0, %[word], c1, c0, 0"
72+
: [word] "=r" (-> usize));
73+
return word;
74+
}
75+
76+
pub fn scr() u32 {
77+
var word = asm("mrc p15, 0, %[word], c1, c1, 0"
78+
: [word] "=r" (-> usize));
79+
return word;
80+
}
81+
82+
pub fn dsbSt() void {
83+
if (build_options.subarch >= 7) {
84+
asm volatile("dsb st");
85+
} else {
86+
asm volatile("mcr p15, 0, r0, c7, c10, 4"
87+
:
88+
:
89+
: "r0");
90+
}
91+
}
92+
93+
pub fn setVectorBaseAddressRegister(address: u32) void {
94+
asm volatile("mcr p15, #0, %[address], cr12, cr0, 0"
95+
:
96+
: [address] "{r0}" (address)
97+
);
98+
}
99+
100+
// The linker will make the address of these global variables equal
101+
// to the value we are interested in. The memory at the address
102+
// could alias any uninitialized global variable in the kernel.
103+
extern var __bss_start: u8;
104+
extern var __bss_end: u8;
105+
extern var __end_init: u8;
106+
107+
pub fn setBssToZero() void {
108+
@memset((*volatile [1]u8)(&__bss_start), 0, @ptrToInt(&__bss_end) - @ptrToInt(&__bss_start));
109+
}
110+
111+
const build_options = @import("build_options");
112+
const serial = @import("serial.zig");

src/gpio.zig

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
pub fn setAlt5(pin_number: u32) void {
2+
setPinPull(pin_number, Pull.None);
3+
setPinFunction(pin_number, GPIO_FUNCTION_ALT5);
4+
}
5+
6+
pub fn initOutputPinWithPullNone(pin_number: u32) void {
7+
setPinPull(pin_number, Pull.None);
8+
setPinFunction(pin_number, GPIO_FUNCTION_OUT);
9+
}
10+
11+
pub fn setPinOutputBool(pin_number: u32, onOrOff: bool) void {
12+
if (onOrOff) {
13+
pins_set.write(pin_number, 1);
14+
} else {
15+
pins_clear.write(pin_number, 1);
16+
}
17+
}
18+
19+
fn setPinPull(pin_number: u32, pull: Pull) void {
20+
GPPUD.* = @enumToInt(pull);
21+
arm.delay(150);
22+
pins_pull.write(pin_number, 1);
23+
arm.delay(150);
24+
GPPUD.* = @enumToInt(Pull.None);
25+
pins_pull.write(pin_number, 0);
26+
}
27+
28+
fn setPinFunction(pin_number: u32, function: u32) void {
29+
pins_function.write(pin_number, function);
30+
}
31+
32+
pub fn ioArrayOf(base: u32, field_size: u32, length: u32) type {
33+
var IoArray = struct {
34+
const Self = @This();
35+
36+
fn write(self: Self, index: u32, value: u32) void {
37+
const field_mask = u32(1) << @intCast(u5, field_size - 1);
38+
rangeCheck(index, length - 1);
39+
rangeCheck(value, field_mask);
40+
const fields_per_word = 32 / field_size;
41+
const register = @intToPtr(*volatile u32, base + (index / fields_per_word) * 4);
42+
const shift = @intCast(u5, (index % fields_per_word) * field_size);
43+
var word = register.*;
44+
word &= ~(field_mask << shift);
45+
word |= value << shift;
46+
register.* = word;
47+
}
48+
};
49+
return IoArray;
50+
}
51+
52+
fn rangeCheck(x: u32, max: u32) void {
53+
if (x > max) {
54+
panicf("{} exceeds max {}", x, max);
55+
}
56+
}
57+
58+
const pins_set: ioArrayOf(GPSET0, 1, GPIO_MAX_PIN) = undefined;
59+
const pins_clear: ioArrayOf(GPCLR0, 1, GPIO_MAX_PIN) = undefined;
60+
const pins_pull: ioArrayOf(GPPUDCLK0, 1, GPIO_MAX_PIN) = undefined;
61+
const pins_function: ioArrayOf(GPFSEL0, 3, GPIO_MAX_PIN) = undefined;
62+
63+
const GPIO_MAX_PIN = 53;
64+
65+
const GPFSEL0 = PERIPHERAL_BASE + 0x200000;
66+
const GPSET0 = PERIPHERAL_BASE + 0x20001C;
67+
const GPCLR0 = PERIPHERAL_BASE + 0x200028;
68+
const GPPUD = arm.io(0x200094);
69+
const GPPUDCLK0 = PERIPHERAL_BASE + 0x200098;
70+
71+
const Pull = enum {
72+
None,
73+
Down,
74+
Up,
75+
};
76+
77+
const GPIO_FUNCTION_FIELD_SIZE: u32 = 3;
78+
const GPIO_FUNCTION_OUT: u32 = 1;
79+
const GPIO_FUNCTION_ALT5: u32 = 2;
80+
81+
const arm = @import("arm_assembly_code.zig");
82+
const panicf = arm.panicf;
83+
const PERIPHERAL_BASE = arm.PERIPHERAL_BASE;

0 commit comments

Comments
 (0)