diff --git a/.06_random/Makefile b/.06_random/Makefile deleted file mode 100644 index f6ba7559..00000000 --- a/.06_random/Makefile +++ /dev/null @@ -1,43 +0,0 @@ -# -# Copyright (C) 2018 bzt (bztsrc@github) -# -# Permission is hereby granted, free of charge, to any person -# obtaining a copy of this software and associated documentation -# files (the "Software"), to deal in the Software without -# restriction, including without limitation the rights to use, copy, -# modify, merge, publish, distribute, sublicense, and/or sell copies -# of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -# DEALINGS IN THE SOFTWARE. -# -# - -SRCS = $(wildcard *.c) -OBJS = $(SRCS:.c=.o) -CFLAGS = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles - -all: clean kernel8.img - -start.o: start.S - aarch64-elf-gcc $(CFLAGS) -c start.S -o start.o - -%.o: %.c - aarch64-elf-gcc $(CFLAGS) -c $< -o $@ - -kernel8.img: start.o $(OBJS) - aarch64-elf-ld -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf - aarch64-elf-objcopy -O binary kernel8.elf kernel8.img - -clean: - rm kernel8.elf *.o >/dev/null 2>/dev/null || true diff --git a/.06_random/OLVASSEL.md b/.06_random/OLVASSEL.md deleted file mode 100644 index 246e70f4..00000000 --- a/.06_random/OLVASSEL.md +++ /dev/null @@ -1,19 +0,0 @@ -Oktatóanyag 06 - Hardveres Véletlenszám Generátor -================================================= - -Ez egy egyszerű okatatóanyag lesz. Lekérjük az aktuális értéket (az egyéként nem dokumentált) -hardveres véletlenszám generátorból. Ez arra használható többek között, hogy egy egyszerű, megfelelő -kockadobást szimuláljunk bármilyen játékban. Ez azért fontos, mert hardveres támogatás nélkül csak -kizárólag pszeudo-véletlen állítható elő. - -Rand.h, rand.c --------------- - -`rand_init()` inicializálja a hardvert. - -`rand(min,max)` visszaad egy min és max közötti véletlen számot. - -Main ----- - -Lekérjük a véletlen számot, és kiírjuk a soros konzolra. diff --git a/.06_random/README.md b/.06_random/README.md deleted file mode 100644 index fd414301..00000000 --- a/.06_random/README.md +++ /dev/null @@ -1,18 +0,0 @@ -Tutorial 06 - Hardware Random Number Generator -============================================== - -This going to be an easy tutorial. We query a number from the (undocumented) hardware random -number generator. You can use this to implement a simple, but accurate dice throw in any game. -It is important as without hardware support you can only generate pseudo-random numbers. - -Rand.h, rand.c --------------- - -`rand_init()` initializes the hardware. - -`rand(min,max)` returns a random number between min and max. - -Main ----- - -We query a random value and then we display it on the serial console. diff --git a/.06_random/gpio.h b/.06_random/gpio.h deleted file mode 100644 index 52fa671d..00000000 --- a/.06_random/gpio.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -#define MMIO_BASE 0x3F000000 - -#define GPFSEL0 ((volatile unsigned int*)(MMIO_BASE+0x00200000)) -#define GPFSEL1 ((volatile unsigned int*)(MMIO_BASE+0x00200004)) -#define GPFSEL2 ((volatile unsigned int*)(MMIO_BASE+0x00200008)) -#define GPFSEL3 ((volatile unsigned int*)(MMIO_BASE+0x0020000C)) -#define GPFSEL4 ((volatile unsigned int*)(MMIO_BASE+0x00200010)) -#define GPFSEL5 ((volatile unsigned int*)(MMIO_BASE+0x00200014)) -#define GPSET0 ((volatile unsigned int*)(MMIO_BASE+0x0020001C)) -#define GPSET1 ((volatile unsigned int*)(MMIO_BASE+0x00200020)) -#define GPCLR0 ((volatile unsigned int*)(MMIO_BASE+0x00200028)) -#define GPLEV0 ((volatile unsigned int*)(MMIO_BASE+0x00200034)) -#define GPLEV1 ((volatile unsigned int*)(MMIO_BASE+0x00200038)) -#define GPEDS0 ((volatile unsigned int*)(MMIO_BASE+0x00200040)) -#define GPEDS1 ((volatile unsigned int*)(MMIO_BASE+0x00200044)) -#define GPHEN0 ((volatile unsigned int*)(MMIO_BASE+0x00200064)) -#define GPHEN1 ((volatile unsigned int*)(MMIO_BASE+0x00200068)) -#define GPPUD ((volatile unsigned int*)(MMIO_BASE+0x00200094)) -#define GPPUDCLK0 ((volatile unsigned int*)(MMIO_BASE+0x00200098)) -#define GPPUDCLK1 ((volatile unsigned int*)(MMIO_BASE+0x0020009C)) diff --git a/.06_random/kernel8.img b/.06_random/kernel8.img deleted file mode 100755 index 00482c06..00000000 Binary files a/.06_random/kernel8.img and /dev/null differ diff --git a/.06_random/main.c b/.06_random/main.c deleted file mode 100644 index 3eae8e0f..00000000 --- a/.06_random/main.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -#include "uart.h" -#include "rand.h" - -void main() -{ - // set up serial console and random number generator - uart_init(); - rand_init(); - - uart_puts("Here goes a random number: "); - uart_hex(rand(0,4294967295)); - uart_puts("\n"); - - // echo everything back - while(1) { - uart_send(uart_getc()); - } -} diff --git a/.06_random/mbox.c b/.06_random/mbox.c deleted file mode 100644 index f750c3e4..00000000 --- a/.06_random/mbox.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -#include "gpio.h" - -/* mailbox message buffer */ -volatile unsigned int __attribute__((aligned(16))) mbox[36]; - -#define VIDEOCORE_MBOX (MMIO_BASE+0x0000B880) -#define MBOX_READ ((volatile unsigned int*)(VIDEOCORE_MBOX+0x0)) -#define MBOX_POLL ((volatile unsigned int*)(VIDEOCORE_MBOX+0x10)) -#define MBOX_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX+0x14)) -#define MBOX_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX+0x18)) -#define MBOX_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX+0x1C)) -#define MBOX_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX+0x20)) -#define MBOX_RESPONSE 0x80000000 -#define MBOX_FULL 0x80000000 -#define MBOX_EMPTY 0x40000000 - -/** - * Make a mailbox call. Returns 0 on failure, non-zero on success - */ -int mbox_call(unsigned char ch) -{ - unsigned int r; - /* wait until we can write to the mailbox */ - do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_FULL); - /* write the address of our message to the mailbox with channel identifier */ - *MBOX_WRITE = (((unsigned int)((unsigned long)&mbox)&~0xF) | (ch&0xF)); - /* now wait for the response */ - while(1) { - /* is there a response? */ - do{asm volatile("nop");}while(*MBOX_STATUS & MBOX_EMPTY); - r=*MBOX_READ; - /* is it a response to our message? */ - if((unsigned char)(r&0xF)==ch && (r&~0xF)==(unsigned int)((unsigned long)&mbox)) - /* is it a valid successful response? */ - return mbox[1]==MBOX_RESPONSE; - } - return 0; -} diff --git a/.06_random/mbox.h b/.06_random/mbox.h deleted file mode 100644 index ab9e61bf..00000000 --- a/.06_random/mbox.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -/* a properly aligned buffer */ -extern volatile unsigned int mbox[36]; - -#define MBOX_REQUEST 0 - -/* channels */ -#define MBOX_CH_POWER 0 -#define MBOX_CH_FB 1 -#define MBOX_CH_VUART 2 -#define MBOX_CH_VCHIQ 3 -#define MBOX_CH_LEDS 4 -#define MBOX_CH_BTNS 5 -#define MBOX_CH_TOUCH 6 -#define MBOX_CH_COUNT 7 -#define MBOX_CH_PROP 8 - -/* tags */ -#define MBOX_TAG_SETCLKRATE 0x38002 -#define MBOX_TAG_LAST 0 - -int mbox_call(unsigned char ch); diff --git a/.06_random/rand.c b/.06_random/rand.c deleted file mode 100644 index 4a15a1d3..00000000 --- a/.06_random/rand.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -#include "gpio.h" - -#define RNG_CTRL ((volatile unsigned int*)(MMIO_BASE+0x00104000)) -#define RNG_STATUS ((volatile unsigned int*)(MMIO_BASE+0x00104004)) -#define RNG_DATA ((volatile unsigned int*)(MMIO_BASE+0x00104008)) -#define RNG_INT_MASK ((volatile unsigned int*)(MMIO_BASE+0x00104010)) - -/** - * Initialize the RNG - */ -void rand_init() -{ - *RNG_STATUS=0x40000; - // mask interrupt - *RNG_INT_MASK|=1; - // enable - *RNG_CTRL|=1; - // wait for gaining some entropy - while(!((*RNG_STATUS)>>24)) asm volatile("nop"); -} - -/** - * Return a random number between [min..max] - */ -unsigned int rand(unsigned int min, unsigned int max) -{ - return *RNG_DATA % (max-min) + min; -} diff --git a/.06_random/rand.h b/.06_random/rand.h deleted file mode 100644 index cd2786b4..00000000 --- a/.06_random/rand.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -void rand_init(); -unsigned int rand(unsigned int min, unsigned int max); diff --git a/.06_random/uart.c b/.06_random/uart.c deleted file mode 100644 index cda6ab88..00000000 --- a/.06_random/uart.c +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -#include "gpio.h" -#include "mbox.h" - -/* PL011 UART registers */ -#define UART0_DR ((volatile unsigned int*)(MMIO_BASE+0x00201000)) -#define UART0_FR ((volatile unsigned int*)(MMIO_BASE+0x00201018)) -#define UART0_IBRD ((volatile unsigned int*)(MMIO_BASE+0x00201024)) -#define UART0_FBRD ((volatile unsigned int*)(MMIO_BASE+0x00201028)) -#define UART0_LCRH ((volatile unsigned int*)(MMIO_BASE+0x0020102C)) -#define UART0_CR ((volatile unsigned int*)(MMIO_BASE+0x00201030)) -#define UART0_IMSC ((volatile unsigned int*)(MMIO_BASE+0x00201038)) -#define UART0_ICR ((volatile unsigned int*)(MMIO_BASE+0x00201044)) - -/** - * Set baud rate and characteristics (115200 8N1) and map to GPIO - */ -void uart_init() -{ - register unsigned int r; - - /* initialize UART */ - *UART0_CR = 0; // turn off UART0 - - /* set up clock for consistent divisor values */ - mbox[0] = 8*4; - mbox[1] = MBOX_REQUEST; - mbox[2] = MBOX_TAG_SETCLKRATE; // set clock rate - mbox[3] = 12; - mbox[4] = 8; - mbox[5] = 2; // UART clock - mbox[6] = 4000000; // 4Mhz - mbox[7] = MBOX_TAG_LAST; - mbox_call(MBOX_CH_PROP); - - /* map UART0 to GPIO pins */ - r=*GPFSEL1; - r&=~((7<<12)|(7<<15)); // gpio14, gpio15 - r|=(4<<12)|(4<<15); // alt0 - *GPFSEL1 = r; - *GPPUD = 0; // enable pins 14 and 15 - r=150; while(r--) { asm volatile("nop"); } - *GPPUDCLK0 = (1<<14)|(1<<15); - r=150; while(r--) { asm volatile("nop"); } - *GPPUDCLK0 = 0; // flush GPIO setup - - *UART0_ICR = 0x7FF; // clear interrupts - *UART0_IBRD = 2; // 115200 baud - *UART0_FBRD = 0xB; - *UART0_LCRH = 0b11<<5; // 8n1 - *UART0_CR = 0x301; // enable Tx, Rx, FIFO -} - -/** - * Send a character - */ -void uart_send(unsigned int c) { - /* wait until we can send */ - do{asm volatile("nop");}while(*UART0_FR&0x20); - /* write the character to the buffer */ - *UART0_DR=c; -} - -/** - * Receive a character - */ -char uart_getc() { - char r; - /* wait until something is in the buffer */ - do{asm volatile("nop");}while(*UART0_FR&0x10); - /* read it and return */ - r=(char)(*UART0_DR); - /* convert carrige return to newline */ - return r=='\r'?'\n':r; -} - -/** - * Display a string - */ -void uart_puts(char *s) { - while(*s) { - /* convert newline to carrige return + newline */ - if(*s=='\n') - uart_send('\r'); - uart_send(*s++); - } -} - -/** - * Display a binary value in hexadecimal - */ -void uart_hex(unsigned int d) { - unsigned int n; - int c; - for(c=28;c>=0;c-=4) { - // get highest tetrad - n=(d>>c)&0xF; - // 0-9 => '0'-'9', 10-15 => 'A'-'F' - n+=n>9?0x37:0x30; - uart_send(n); - } -} diff --git a/.06_random/uart.h b/.06_random/uart.h deleted file mode 100644 index 99b2be48..00000000 --- a/.06_random/uart.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2018 bzt (bztsrc@github) - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, copy, - * modify, merge, publish, distribute, sublicense, and/or sell copies - * of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -void uart_init(); -void uart_send(unsigned int c); -char uart_getc(); -void uart_puts(char *s); -void uart_hex(unsigned int d); diff --git a/06_random/Cargo.lock b/06_random/Cargo.lock new file mode 100644 index 00000000..6423a007 --- /dev/null +++ b/06_random/Cargo.lock @@ -0,0 +1,35 @@ +[[package]] +name = "kernel8" +version = "0.1.0" +dependencies = [ + "raspi3_glue 0.1.0", + "rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "raspi3_glue" +version = "0.1.0" + +[[package]] +name = "rlibc" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vcell" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "volatile-register" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum rlibc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc874b127765f014d792f16763a81245ab80500e2ad921ed4ee9e82481ee08fe" +"checksum vcell 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "45c297f0afb6928cd08ab1ff9d95e99392595ea25ae1b5ecf822ff8764e57a0d" +"checksum volatile-register 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" diff --git a/06_random/Cargo.toml b/06_random/Cargo.toml new file mode 100644 index 00000000..8e79f96f --- /dev/null +++ b/06_random/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "kernel8" +version = "0.1.0" +authors = ["Andre Richter "] + +[dependencies] +raspi3_glue = { path = "raspi3_glue" } +volatile-register = "0.2.0" +rlibc = "1.0" diff --git a/06_random/Makefile b/06_random/Makefile new file mode 100644 index 00000000..fb7767f3 --- /dev/null +++ b/06_random/Makefile @@ -0,0 +1,61 @@ +# +# MIT License +# +# Copyright (c) 2018 Andre Richter +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +TARGET = aarch64-raspi3-none-elf + +CROSS_CONTAINER = ./dockcross-linux-aarch64 +CROSS_CONTAINER_OBJCOPY = aarch64-linux-gnu-objcopy + +QEMU_CONTAINER = andrerichter/raspi3-qemu +DOCKER_CMD = docker run -it --rm -v $(shell pwd):/work -w /work +QEMU_CMD = qemu-system-aarch64 -M raspi3 -kernel kernel8.img + +all: clean kernel8.img + +target/$(TARGET)/debug/kernel8: src/main.rs + RUST_TARGET_PATH=$(shell pwd) xargo build --target=$(TARGET) + cp $@ . + +target/$(TARGET)/release/kernel8: src/main.rs + RUST_TARGET_PATH=$(shell pwd) xargo build --target=$(TARGET) --release + cp $@ . + +ifeq ($(DEBUG),1) +kernel8: target/$(TARGET)/debug/kernel8 +else +kernel8: target/$(TARGET)/release/kernel8 +endif + +kernel8.img: kernel8 + $(CROSS_CONTAINER) $(CROSS_CONTAINER_OBJCOPY) -O binary -S $< kernel8.img + +qemu: + $(DOCKER_CMD) $(QEMU_CONTAINER) $(QEMU_CMD) -serial stdio + +clippy: + RUSTFLAGS="-C panic=abort" xargo clippy --target=$(TARGET) + +clean: + cargo clean + rm -f kernel8 diff --git a/06_random/README.md b/06_random/README.md new file mode 100644 index 00000000..3489c004 --- /dev/null +++ b/06_random/README.md @@ -0,0 +1,17 @@ +# Tutorial 06 - Hardware Random Number Generator + +This going to be an easy tutorial. We query a number from the (undocumented) +hardware random number generator. You can use this to implement a simple, but +accurate dice throw in any game. It is important as without hardware support +you can only generate pseudo-random numbers. + +## rand.s + +`Rng::init(&self)` initializes the hardware. + +`Rng::rand(&self, min: u32, max: u32)` returns a random number between min and +max. + +## main.rs + +Press a key to query a random value and then display it on the serial console. diff --git a/06_random/aarch64-raspi3-none-elf.json b/06_random/aarch64-raspi3-none-elf.json new file mode 100644 index 00000000..407f21b8 --- /dev/null +++ b/06_random/aarch64-raspi3-none-elf.json @@ -0,0 +1,24 @@ +{ + "arch": "aarch64", + "data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128", + "executables": true, + "linker-flavor": "ld.lld", + "linker-is-gnu": true, + "pre-link-args": { + "ld.lld": [ + "--script=link.ld" + ] + }, + "llvm-target": "aarch64-unknown-none", + "no-compiler-rt": true, + "features": "+a53,+strict-align", + "max-atomic-width": 128, + "os": "none", + "panic": "abort", + "panic-strategy": "abort", + "relocation-model": "pic", + "target-c-int-width": "32", + "target-endian": "little", + "target-pointer-width": "64", + "disable-redzone": true +} diff --git a/06_random/dockcross-linux-aarch64 b/06_random/dockcross-linux-aarch64 new file mode 100755 index 00000000..3c7481d2 --- /dev/null +++ b/06_random/dockcross-linux-aarch64 @@ -0,0 +1,246 @@ +#!/bin/bash + +DEFAULT_DOCKCROSS_IMAGE=dockcross/linux-arm64 + +#------------------------------------------------------------------------------ +# Helpers +# +err() { + echo -e >&2 ERROR: $@\\n +} + +die() { + err $@ + exit 1 +} + +has() { + # eg. has command update + local kind=$1 + local name=$2 + + type -t $kind:$name | grep -q function +} + +#------------------------------------------------------------------------------ +# Command handlers +# +command:update-image() { + docker pull $FINAL_IMAGE +} + +help:update-image() { + echo Pull the latest $FINAL_IMAGE . +} + +command:update-script() { + if cmp -s <( docker run --rm $FINAL_IMAGE ) $0; then + echo $0 is up to date + else + echo -n Updating $0 '... ' + docker run --rm $FINAL_IMAGE > $0 && echo ok + fi +} + +help:update-image() { + echo Update $0 from $FINAL_IMAGE . +} + +command:update() { + command:update-image + command:update-script +} + +help:update() { + echo Pull the latest $FINAL_IMAGE, and then update $0 from that. +} + +command:help() { + if [[ $# != 0 ]]; then + if ! has command $1; then + err \"$1\" is not an dockcross command + command:help + elif ! has help $1; then + err No help found for \"$1\" + else + help:$1 + fi + else + cat >&2 < +ENDHELP + exit 1 + fi +} + +#------------------------------------------------------------------------------ +# Option processing +# +special_update_command='' +while [[ $# != 0 ]]; do + case $1 in + + --) + shift + break + ;; + + --args|-a) + ARG_ARGS="$2" + shift 2 + ;; + + --config|-c) + ARG_CONFIG="$2" + shift 2 + ;; + + --image|-i) + ARG_IMAGE="$2" + shift 2 + ;; + update|update-image|update-script) + special_update_command=$1 + break + ;; + -*) + err Unknown option \"$1\" + command:help + exit + ;; + + *) + break + ;; + + esac +done + +# The precedence for options is: +# 1. command-line arguments +# 2. environment variables +# 3. defaults + +# Source the config file if it exists +DEFAULT_DOCKCROSS_CONFIG=~/.dockcross +FINAL_CONFIG=${ARG_CONFIG-${DOCKCROSS_CONFIG-$DEFAULT_DOCKCROSS_CONFIG}} + +[[ -f "$FINAL_CONFIG" ]] && source "$FINAL_CONFIG" + +# Set the docker image +FINAL_IMAGE=${ARG_IMAGE-${DOCKCROSS_IMAGE-$DEFAULT_DOCKCROSS_IMAGE}} + +# Handle special update command +if [ "$special_update_command" != "" ]; then + case $special_update_command in + + update) + command:update + exit $? + ;; + + update-image) + command:update-image + exit $? + ;; + + update-script) + command:update-script + exit $? + ;; + + esac +fi + +# Set the docker run extra args (if any) +FINAL_ARGS=${ARG_ARGS-${DOCKCROSS_ARGS}} + +# Bash on Ubuntu on Windows +UBUNTU_ON_WINDOWS=$([ -e /proc/version ] && grep -l Microsoft /proc/version || echo "") +# MSYS, Git Bash, etc. +MSYS=$([ -e /proc/version ] && grep -l MINGW /proc/version || echo "") + +if [ -z "$UBUNTU_ON_WINDOWS" -a -z "$MSYS" ]; then + USER_IDS="-e BUILDER_UID=$( id -u ) -e BUILDER_GID=$( id -g ) -e BUILDER_USER=$( id -un ) -e BUILDER_GROUP=$( id -gn )" +fi + +# Change the PWD when working in Docker on Windows +if [ -n "$UBUNTU_ON_WINDOWS" ]; then + HOST_PWD=$PWD + HOST_PWD=${HOST_PWD/\/mnt\//} + HOST_PWD=${HOST_PWD/\//:\/} +elif [ -n "$MSYS" ]; then + HOST_PWD=$PWD + HOST_PWD=${HOST_PWD/\//} + HOST_PWD=${HOST_PWD/\//:\/} +else + HOST_PWD=$PWD +fi + +# Mount Additional Volumes +if [ -z "$SSH_DIR" ]; then + SSH_DIR="$HOME/.ssh" +fi + +HOST_VOLUMES= +if [ -e "$SSH_DIR" ]; then + HOST_VOLUMES+="-v $SSH_DIR:/home/$(id -un)/.ssh" +fi + +#------------------------------------------------------------------------------ +# Now, finally, run the command in a container +# +tty -s && TTY_ARGS=-ti || TTY_ARGS= +CONTAINER_NAME=dockcross_$RANDOM +docker run $TTY_ARGS --name $CONTAINER_NAME \ + -v "$HOST_PWD":/work \ + $HOST_VOLUMES \ + $USER_IDS \ + $FINAL_ARGS \ + $FINAL_IMAGE "$@" +run_exit_code=$? + +# Attempt to delete container +rm_output=$(docker rm -f $CONTAINER_NAME 2>&1) +rm_exit_code=$? +if [[ $rm_exit_code != 0 ]]; then + if [[ "$CIRCLECI" == "true" ]] && [[ $rm_output == *"Driver btrfs failed to remove"* ]]; then + : # Ignore error because of https://circleci.com/docs/docker-btrfs-error/ + else + echo "$rm_output" + exit $rm_exit_code + fi +fi + +exit $run_exit_code + +################################################################################ +# +# This image is not intended to be run manually. +# +# To create a dockcross helper script for the +# dockcross/linux-armv7 image, run: +# +# docker run --rm dockcross/linux-armv7 > dockcross-linux-armv7 +# chmod +x dockcross-linux-armv7 +# +# You may then wish to move the dockcross script to your PATH. +# +################################################################################ diff --git a/06_random/kernel8.img b/06_random/kernel8.img new file mode 100755 index 00000000..aa04376f Binary files /dev/null and b/06_random/kernel8.img differ diff --git a/.06_random/link.ld b/06_random/link.ld similarity index 100% rename from .06_random/link.ld rename to 06_random/link.ld diff --git a/06_random/raspi3_glue/Cargo.toml b/06_random/raspi3_glue/Cargo.toml new file mode 100644 index 00000000..99c8e683 --- /dev/null +++ b/06_random/raspi3_glue/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "raspi3_glue" +version = "0.1.0" +authors = ["Andre Richter "] + +[dependencies] diff --git a/.06_random/start.S b/06_random/raspi3_glue/src/boot_cores.S similarity index 84% rename from .06_random/start.S rename to 06_random/raspi3_glue/src/boot_cores.S index 27d0c503..f6f28af6 100644 --- a/.06_random/start.S +++ b/06_random/raspi3_glue/src/boot_cores.S @@ -1,5 +1,6 @@ /* * Copyright (C) 2018 bzt (bztsrc@github) + * Copyright (c) 2018 Andre Richter * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -25,9 +26,9 @@ .section ".text.boot" -.global _start +.global _boot_cores -_start: +_boot_cores: // read cpu id, stop slave cores mrs x1, mpidr_el1 and x1, x1, #3 @@ -38,18 +39,10 @@ _start: 2: // cpu id == 0 // set stack before our code - ldr x1, =_start + ldr x1, =_boot_cores mov sp, x1 - // clear bss - ldr x1, =__bss_start - ldr w2, =__bss_size -3: cbz w2, 4f - str xzr, [x1], #8 - sub w2, w2, #1 - cbnz w2, 3b - - // jump to C code, should not return -4: bl main + // jump to Rust code, should not return + bl reset // for failsafe, halt this core too b 1b diff --git a/06_random/raspi3_glue/src/lib.rs b/06_random/raspi3_glue/src/lib.rs new file mode 100644 index 00000000..e1d22891 --- /dev/null +++ b/06_random/raspi3_glue/src/lib.rs @@ -0,0 +1,88 @@ +/* + * MIT License + * + * Copyright (c) 2018 Jorge Aparicio + * Copyright (c) 2018 Andre Richter + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#![feature(lang_items)] +#![no_std] +#![feature(global_asm)] + +use core::ptr; + +#[lang = "panic_fmt"] +unsafe extern "C" fn panic_fmt( + _args: core::fmt::Arguments, + _file: &'static str, + _line: u32, + _col: u32, +) -> ! { + loop {} +} + +#[lang = "start"] +extern "C" fn start(user_main: fn() -> T, _argc: isize, _argv: *const *const u8) -> isize +where + T: Termination, +{ + user_main().report() as isize +} + +#[lang = "termination"] +trait Termination { + fn report(self) -> i32; +} + +impl Termination for () { + fn report(self) -> i32 { + 0 + } +} + +#[no_mangle] +pub unsafe extern "C" fn reset() -> ! { + extern "C" { + fn main(argc: isize, argv: *const *const u8) -> isize; + + static mut __bss_start: u32; + static mut __bss_end: u32; + } + + zero_bss(&mut __bss_start, &mut __bss_end); + + main(0, ptr::null()); + + loop {} +} + +unsafe fn zero_bss(bss_start: *mut u32, bss_end: *mut u32) { + let mut bss = bss_start; + while bss < bss_end { + // NOTE(ptr::write*) to force aligned stores + // NOTE(volatile) to prevent the compiler from optimizing this into `memclr` + ptr::write_volatile(bss, 0); + bss = bss.offset(1); + } +} + +// Disable all cores except core 0, and then jump to reset() +global_asm!(include_str!("boot_cores.S")); diff --git a/06_random/src/gpio.rs b/06_random/src/gpio.rs new file mode 100644 index 00000000..9db608e8 --- /dev/null +++ b/06_random/src/gpio.rs @@ -0,0 +1,30 @@ +/* + * MIT License + * + * Copyright (c) 2018 Andre Richter + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +use volatile_register::RW; +use super::MMIO_BASE; + +pub const GPFSEL1: *const RW = (MMIO_BASE + 0x0020_0004) as *const RW; +pub const GPPUD: *const RW = (MMIO_BASE + 0x0020_0094) as *const RW; +pub const GPPUDCLK0: *const RW = (MMIO_BASE + 0x0020_0098) as *const RW; diff --git a/06_random/src/main.rs b/06_random/src/main.rs new file mode 100644 index 00000000..248ee603 --- /dev/null +++ b/06_random/src/main.rs @@ -0,0 +1,65 @@ +/* + * MIT License + * + * Copyright (c) 2018 Andre Richter + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#![no_std] +#![feature(asm)] + +extern crate raspi3_glue; +extern crate rlibc; // for memset et al.b +extern crate volatile_register; + +const MMIO_BASE: u32 = 0x3F00_0000; + +mod mbox; +mod gpio; +mod uart; +mod rand; + +fn main() { + let mut mbox = mbox::Mbox::new(); + let uart = uart::Uart::new(); + + // set up serial console + if uart.init(&mut mbox).is_err() { + return; // If UART fails, abort early + } + + uart.getc(); // Press a key first before being greeted + uart.puts("Hello Rustacean!\n"); + + // set up random number generator + let rng = rand::Rng::new(); + rng.init(); + + uart.puts("Press any key to generate random numbers.\n"); + + // echo everything back + loop { + uart.getc(); + + uart.puts("0x"); + uart.hex(rng.rand(0, 4_294_967_295)); + uart.puts("\n"); + } +} diff --git a/06_random/src/mbox.rs b/06_random/src/mbox.rs new file mode 100644 index 00000000..7dc95d01 --- /dev/null +++ b/06_random/src/mbox.rs @@ -0,0 +1,139 @@ +/* + * MIT License + * + * Copyright (c) 2018 Andre Richter + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +use super::MMIO_BASE; +use volatile_register::{RO, WO}; + +pub const VIDEOCORE_MBOX: u32 = MMIO_BASE + 0xB880; + +#[allow(non_snake_case)] +#[repr(C, packed)] +pub struct Registers { + READ: RO, // 0x00 + reserved: [u8; 0xC], // 0x04 + POLL: RO, // 0x10 + SENDER: RO, // 0x14 + STATUS: RO, // 0x18 + CONFIG: RO, // 0x1C + WRITE: WO, // 0x20 +} + +// Custom errors +pub enum MboxError { + ResponseError, + UnknownError, +} +pub type Result = ::core::result::Result; + +// Channels +pub mod channel { + pub const PROP: u32 = 8; +} + +// Tags +pub mod tag { + pub const SETCLKRATE: u32 = 0x38002; + pub const LAST: u32 = 0; +} + +// Clocks +pub mod clock { + pub const UART: u32 = 0x0_0000_0002; +} + +// Responses +mod response { + pub const SUCCESS: u32 = 0x8000_0000; + pub const ERROR: u32 = 0x8000_0001; // error parsing request buffer (partial response) +} + +pub const REQUEST: u32 = 0; +const FULL: u32 = 0x8000_0000; +const EMPTY: u32 = 0x4000_0000; + +// Public interface to the mailbox +#[repr(C)] +pub struct Mbox { + // The address for buffer needs to be 16-byte aligned so that the + // Videcore can handle it properly. We don't take precautions here + // to achieve that, but for now it just works. Since alignment of + // data structures in Rust is a bit of a hassle right now, we just + // close our eyes and roll with it. + pub buffer: [u32; 36], + registers: *const Registers, +} + +impl Mbox { + pub fn new() -> Mbox { + Mbox { + buffer: [0; 36], + registers: VIDEOCORE_MBOX as *const Registers, + } + } + + /// Make a mailbox call. Returns Err(MboxError) on failure, Ok(()) success + pub fn call(&mut self, channel: u32) -> Result<()> { + // wait until we can write to the mailbox + loop { + unsafe { + if ((*self.registers).STATUS.read() & FULL) != FULL { + break; + } + asm!("nop" :::: "volatile"); + } + } + + // write the address of our message to the mailbox with channel identifier + unsafe { + (*self.registers) + .WRITE + .write(((self.buffer.as_mut_ptr() as u32) & !0xF) | (channel & 0xF)); + } + + // now wait for the response + loop { + // is there a response? + loop { + unsafe { + if ((*self.registers).STATUS.read() & EMPTY) != EMPTY { + break; + } + asm!("nop" :::: "volatile"); + } + } + + let resp: u32 = unsafe { (*self.registers).READ.read() }; + + // is it a response to our message? + if ((resp & 0xF) == channel) && ((resp & !0xF) == (self.buffer.as_mut_ptr() as u32)) { + // is it a valid successful response? + return match self.buffer[1] { + response::SUCCESS => Ok(()), + response::ERROR => Err(MboxError::ResponseError), + _ => Err(MboxError::UnknownError), + }; + } + } + } +} diff --git a/06_random/src/rand.rs b/06_random/src/rand.rs new file mode 100644 index 00000000..4607f670 --- /dev/null +++ b/06_random/src/rand.rs @@ -0,0 +1,80 @@ +/* + * MIT License + * + * Copyright (c) 2018 Andre Richter + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +use super::MMIO_BASE; +use volatile_register::*; + +pub const RNG_BASE: u32 = MMIO_BASE + 0x104_000; + +#[allow(non_snake_case)] +#[repr(C)] +struct Registers { + CTRL: RW, // 0x00 + STATUS: RW, // 0x04 + DATA: RO, // 0x08 + _reserved: u32, // 0x0c + INT_MASK: RW, // 0x10 +} + +/// Public interface to the RNG +pub struct Rng { + registers: *const Registers, +} + +impl Rng { + pub fn new() -> Rng { + Rng { + registers: RNG_BASE as *const Registers, + } + } + + /// Initialize the RNG + pub fn init(&self) { + unsafe { + (*self.registers).STATUS.write(0x40_000); + + // mask interrupt + (*self.registers).INT_MASK.modify(|x| x | 1); + + // enable + (*self.registers).CTRL.modify(|x| x | 1); + + // wait for gaining some entropy + loop { + if ((*self.registers).STATUS.read() >> 24) != 0 { + break; + } + + asm!("nop" :::: "volatile"); + } + } + } + + /// Return a random number between [min..max] + pub fn rand(&self, min: u32, max: u32) -> u32 { + let r = unsafe { (*self.registers).DATA.read() }; + + r % (max - min) + min + } +} diff --git a/06_random/src/uart.rs b/06_random/src/uart.rs new file mode 100644 index 00000000..b605f8dc --- /dev/null +++ b/06_random/src/uart.rs @@ -0,0 +1,192 @@ +/* + * MIT License + * + * Copyright (c) 2018 Andre Richter + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +use super::MMIO_BASE; +use volatile_register::*; +use mbox; +use gpio; +use core::sync::atomic::{compiler_fence, Ordering}; + +const UART_BASE: u32 = MMIO_BASE + 0x20_1000; + +// PL011 UART registers +#[allow(non_snake_case)] +#[repr(C, packed)] +struct Registers { + DR: RW, // 0x00 + reserved0: [u8; 0x14], // 0x04 + FR: RO, // 0x18 + reserved1: u64, // 0x1C + IBRD: WO, // 0x24 + FBRD: WO, // 0x28 + LCRH: WO, // 0x2C + CR: WO, // 0x30 + reserved3: [u8; 0x10], // 0x34 + ICR: WO, // 0x44 +} + +pub enum UartError { + MailboxError, +} +pub type Result = ::core::result::Result; + +pub struct Uart { + registers: *const Registers, +} + +impl Uart { + pub fn new() -> Uart { + Uart { + registers: UART_BASE as *const Registers, + } + } + + ///Set baud rate and characteristics (115200 8N1) and map to GPIO + pub fn init(&self, mbox: &mut mbox::Mbox) -> Result<()> { + // turn off UART0 + unsafe { (*self.registers).CR.write(0) }; + + // set up clock for consistent divisor values + mbox.buffer[0] = 9 * 4; + mbox.buffer[1] = mbox::REQUEST; + mbox.buffer[2] = mbox::tag::SETCLKRATE; + mbox.buffer[3] = 12; + mbox.buffer[4] = 8; + mbox.buffer[5] = mbox::clock::UART; // UART clock + mbox.buffer[6] = 4_000_000; // 4Mhz + mbox.buffer[7] = 0; // skip turbo setting + mbox.buffer[8] = mbox::tag::LAST; + + // Insert a compiler fence that ensures that all stores to the + // mbox buffer are finished before the GPU is signaled (which + // is done by a store operation as well). + compiler_fence(Ordering::SeqCst); + + if mbox.call(mbox::channel::PROP).is_err() { + return Err(UartError::MailboxError); // Abort if UART clocks couldn't be set + }; + + // map UART0 to GPIO pins + unsafe { + (*gpio::GPFSEL1).modify(|x| { + // Modify with a closure + let mut ret = x; + ret &= !((7 << 12) | (7 << 15)); // gpio14, gpio15 + ret |= (4 << 12) | (4 << 15); // alt0 + + ret + }); + + (*gpio::GPPUD).write(0); // enable pins 14 and 15 + for _ in 0..150 { + asm!("nop" :::: "volatile"); + } + + (*gpio::GPPUDCLK0).write((1 << 14) | (1 << 15)); + for _ in 0..150 { + asm!("nop" :::: "volatile"); + } + (*gpio::GPPUDCLK0).write(0); + + (*self.registers).ICR.write(0x7FF); // clear interrupts + (*self.registers).IBRD.write(2); // 115200 baud + (*self.registers).FBRD.write(0xB); + (*self.registers).LCRH.write(0b11 << 5); // 8n1 + (*self.registers).CR.write(0x301); // enable Tx, Rx, FIFO + } + + Ok(()) + } + + /// Send a character + pub fn send(&self, c: char) { + unsafe { + // wait until we can send + loop { + if ((*self.registers).FR.read() & 0x20) != 0x20 { + break; + } + asm!("nop" :::: "volatile"); + } + + // write the character to the buffer + (*self.registers).DR.write(c as u32); + } + } + + /// Receive a character + pub fn getc(&self) -> char { + unsafe { + // wait until something is in the buffer + loop { + if ((*self.registers).FR.read() & 0x10) != 0x10 { + break; + } + asm!("nop" :::: "volatile"); + } + } + + // read it and return + let mut ret = unsafe { (*self.registers).DR.read() as u8 as char }; + + // convert carrige return to newline + if ret == '\r' { + ret = '\n' + } + + ret + } + + /// Display a string + pub fn puts(&self, string: &str) { + for c in string.chars() { + // convert newline to carrige return + newline + if c == '\n' { + self.send('\r') + } + + self.send(c); + } + } + + /// Display a binary value in hexadecimal + pub fn hex(&self, d: u32) { + let mut n; + + for i in 0..8 { + // get highest tetrad + n = d.wrapping_shr(28 - i * 4) & 0xF; + + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + // Add proper offset for ASCII table + if n > 9 { + n += 0x37; + } else { + n += 0x30; + } + + self.send(n as u8 as char); + } + } +}