From 78ea9a9931d19d0c6874656251bff65387044089 Mon Sep 17 00:00:00 2001 From: Andre Richter Date: Mon, 2 Apr 2018 18:35:24 +0200 Subject: [PATCH] Add tutorial 04_mailboxes --- .04_mailboxes/Makefile | 43 --- .04_mailboxes/OLVASSEL.md | 41 --- .04_mailboxes/README.md | 41 --- .04_mailboxes/gpio.h | 45 ---- .04_mailboxes/kernel8.img | Bin 984 -> 0 bytes .04_mailboxes/main.c | 60 ----- .04_mailboxes/mbox.c | 63 ----- .04_mailboxes/mbox.h | 46 ---- .04_mailboxes/uart.c | 119 --------- .04_mailboxes/uart.h | 30 --- 04_mailboxes/Cargo.lock | 35 +++ 04_mailboxes/Cargo.toml | 9 + 04_mailboxes/Makefile | 58 +++++ 04_mailboxes/README.md | 73 ++++++ 04_mailboxes/aarch64-raspi3-none-elf.json | 24 ++ 04_mailboxes/dockcross-linux-aarch64 | 246 ++++++++++++++++++ 04_mailboxes/kernel8.img | Bin 0 -> 1920 bytes {.04_mailboxes => 04_mailboxes}/link.ld | 0 04_mailboxes/raspi3_glue/Cargo.toml | 6 + .../raspi3_glue/src/boot_cores.S | 19 +- 04_mailboxes/raspi3_glue/src/lib.rs | 88 +++++++ 04_mailboxes/src/gpio.rs | 30 +++ 04_mailboxes/src/main.rs | 84 ++++++ 04_mailboxes/src/mbox.rs | 134 ++++++++++ 04_mailboxes/src/uart.rs | 169 ++++++++++++ 25 files changed, 962 insertions(+), 501 deletions(-) delete mode 100644 .04_mailboxes/Makefile delete mode 100644 .04_mailboxes/OLVASSEL.md delete mode 100644 .04_mailboxes/README.md delete mode 100644 .04_mailboxes/gpio.h delete mode 100755 .04_mailboxes/kernel8.img delete mode 100644 .04_mailboxes/main.c delete mode 100644 .04_mailboxes/mbox.c delete mode 100644 .04_mailboxes/mbox.h delete mode 100644 .04_mailboxes/uart.c delete mode 100644 .04_mailboxes/uart.h create mode 100644 04_mailboxes/Cargo.lock create mode 100644 04_mailboxes/Cargo.toml create mode 100644 04_mailboxes/Makefile create mode 100644 04_mailboxes/README.md create mode 100644 04_mailboxes/aarch64-raspi3-none-elf.json create mode 100755 04_mailboxes/dockcross-linux-aarch64 create mode 100755 04_mailboxes/kernel8.img rename {.04_mailboxes => 04_mailboxes}/link.ld (100%) create mode 100644 04_mailboxes/raspi3_glue/Cargo.toml rename .04_mailboxes/start.S => 04_mailboxes/raspi3_glue/src/boot_cores.S (84%) create mode 100644 04_mailboxes/raspi3_glue/src/lib.rs create mode 100644 04_mailboxes/src/gpio.rs create mode 100644 04_mailboxes/src/main.rs create mode 100644 04_mailboxes/src/mbox.rs create mode 100644 04_mailboxes/src/uart.rs diff --git a/.04_mailboxes/Makefile b/.04_mailboxes/Makefile deleted file mode 100644 index f6ba7559..00000000 --- a/.04_mailboxes/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/.04_mailboxes/OLVASSEL.md b/.04_mailboxes/OLVASSEL.md deleted file mode 100644 index 767adcb0..00000000 --- a/.04_mailboxes/OLVASSEL.md +++ /dev/null @@ -1,41 +0,0 @@ -Oktatóanyag 04 - Levelesládák -============================= - -Mielőtt nekiugranánk az UART0-ának, szükségünk lesz a levelesládára. Ezért ebben az oktatóanyagban bemutatom a -mailbox interfészt. Arra használjuk, hogy lekérdezzük az alaplap egyedi sorszámát, majd kiírjuk azt. - -FIGYELEM: qemu nem irányítja át alapból az UART1-et a terminálra, csak az UART0-át! - -Uart.h, uart.c --------------- - -`uart_hex(d)` kiír egy bináris értéket hexadecimális formátumban. - -Mbox.h, mbox.c --------------- - -A levelesláda interfésze. Először értékekkel feltöltjük az `mbox` tömböt, aztán meghívjuk a `mbox_call(ch)`-t, -hogy értesüljön róla a GPU, megadva közben a levelesláda csatornáját. -Ebben a példában a [property csatornát](https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface) -használtam, aminek az üzenete a következőképp néz ki: - -``` - 0. üzenet teljes hossza bájtban, (x+1)*4 - 1. MBOX_REQUEST mágikus szám, kérés típusú üzenetet jelent - 2-x. parancsok - x+1. MBOX_TAG_LAST mágikus szám, nincs további parancs jelölése -``` - -Ahol minden egyes parancs szerkezete a következő: - -``` - n+0. parancs azonosító - n+1. adatterület mérete bájtban - n+2. nulla - n+3. opcionális adatterület -``` - -Main ----- - -Lekérjük az alaplap egyedi szériaszámát, majd kiírjuk a soros konzolra. diff --git a/.04_mailboxes/README.md b/.04_mailboxes/README.md deleted file mode 100644 index 2ff4da20..00000000 --- a/.04_mailboxes/README.md +++ /dev/null @@ -1,41 +0,0 @@ -Tutorial 04 - Mailboxes -======================= - -Before we could go on with UART0, we need mailboxes. So in this tutorial we introduce the mailbox interface. -We'll use it to query the board's serial number and print that out on UART1. - -NOTE: qemu does not redirect UART1 to terminal by default, only UART0! - -Uart.h, uart.c --------------- - -`uart_hex(d)` prints out a binary value in hexadecimal format. - -Mbox.h, mbox.c --------------- - -The mailbox interface. First we fill up the message in `mbox` array, then we call -`mbox_call(ch)` to pass it to the GPU, specifying the mailbox channel. -In this example we have used the [property channel](https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface), -which requires the message to be formatted as: - -``` - 0. size of the message in bytes, (x+1)*4 - 1. MBOX_REQUEST magic value, indicates request message - 2-x. tags - x+1. MBOX_TAG_LAST magic value, indicates no more tags -``` - -Where each tag looks like: - -``` - n+0. tag identifier - n+1. value buffer size in bytes - n+2. must be zero - n+3. optional value buffer -``` - -Main ----- - -We query the board's serial number and then we display it on the serial console. diff --git a/.04_mailboxes/gpio.h b/.04_mailboxes/gpio.h deleted file mode 100644 index 52fa671d..00000000 --- a/.04_mailboxes/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/.04_mailboxes/kernel8.img b/.04_mailboxes/kernel8.img deleted file mode 100755 index 19db1d416221740a3b3e32dd2a332776f99d02a2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 984 zcmZ8gOH30{6g|@!3i4^10f96`X0RI5jnN<tz7F|(e zQWF=7(GXX3 zy5;+RS5m>{I8YG%73j_Z{qaTozMx^`vG1Q-0`C1JPKSI=)!(wZuXD(I*`~bLx3l)c zqy$^@-qMl0XTfq$(mz2_oAVwIowWd$b=>2OeWAVv$JU5lqdiZFGLE*qCm4fv4vx3k z?byro1N7gSj@>|eL3ccrzJ^6R!8%bq%9M1+Hm`F6SmO;cX!Ag6i1cgN_}fNIxCg||M;U)Ywz}(XL~9NyDg}+11ooYzc~9jQBgI==G<(B_wM6d%Bm8Z2yh-j zxZ}-mlOc*uzmpQ79D{q5`&DM|+>sTO+6u49btPiCA4GRr?tAKL&IlD=(OwguZ}@zXAyK2`2|Se@;~TgGfEGnt$= vX6CMsr!vOm?0N1Bnkn*Knn{jNr;M97jPzV8Qv;i|^gf8cwg20{z#-!=uMl3^ diff --git a/.04_mailboxes/main.c b/.04_mailboxes/main.c deleted file mode 100644 index 2f4f00e2..00000000 --- a/.04_mailboxes/main.c +++ /dev/null @@ -1,60 +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 "mbox.h" - -void main() -{ - // set up serial console - uart_init(); - - // get the board's unique serial number with a mailbox call - mbox[0] = 8*4; // length of the message - mbox[1] = MBOX_REQUEST; // this is a request message - - mbox[2] = MBOX_TAG_GETSERIAL; // get serial number command - mbox[3] = 8; // buffer size - mbox[4] = 8; - mbox[5] = 0; // clear output buffer - mbox[6] = 0; - - mbox[7] = MBOX_TAG_LAST; - - // send the message to the GPU and receive answer - if (mbox_call(MBOX_CH_PROP)) { - uart_puts("My serial number is: "); - uart_hex(mbox[6]); - uart_hex(mbox[5]); - uart_puts("\n"); - } else { - uart_puts("Unable to query serial!\n"); - } - - // echo everything back - while(1) { - uart_send(uart_getc()); - } -} diff --git a/.04_mailboxes/mbox.c b/.04_mailboxes/mbox.c deleted file mode 100644 index f750c3e4..00000000 --- a/.04_mailboxes/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/.04_mailboxes/mbox.h b/.04_mailboxes/mbox.h deleted file mode 100644 index d1f7a352..00000000 --- a/.04_mailboxes/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_GETSERIAL 0x10004 -#define MBOX_TAG_LAST 0 - -int mbox_call(unsigned char ch); diff --git a/.04_mailboxes/uart.c b/.04_mailboxes/uart.c deleted file mode 100644 index a012a2ec..00000000 --- a/.04_mailboxes/uart.c +++ /dev/null @@ -1,119 +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" - -/* Auxilary mini UART registers */ -#define AUX_ENABLE ((volatile unsigned int*)(MMIO_BASE+0x00215004)) -#define AUX_MU_IO ((volatile unsigned int*)(MMIO_BASE+0x00215040)) -#define AUX_MU_IER ((volatile unsigned int*)(MMIO_BASE+0x00215044)) -#define AUX_MU_IIR ((volatile unsigned int*)(MMIO_BASE+0x00215048)) -#define AUX_MU_LCR ((volatile unsigned int*)(MMIO_BASE+0x0021504C)) -#define AUX_MU_MCR ((volatile unsigned int*)(MMIO_BASE+0x00215050)) -#define AUX_MU_LSR ((volatile unsigned int*)(MMIO_BASE+0x00215054)) -#define AUX_MU_MSR ((volatile unsigned int*)(MMIO_BASE+0x00215058)) -#define AUX_MU_SCRATCH ((volatile unsigned int*)(MMIO_BASE+0x0021505C)) -#define AUX_MU_CNTL ((volatile unsigned int*)(MMIO_BASE+0x00215060)) -#define AUX_MU_STAT ((volatile unsigned int*)(MMIO_BASE+0x00215064)) -#define AUX_MU_BAUD ((volatile unsigned int*)(MMIO_BASE+0x00215068)) - -/** - * Set baud rate and characteristics (115200 8N1) and map to GPIO - */ -void uart_init() -{ - register unsigned int r; - - /* initialize UART */ - *AUX_ENABLE |=1; // enable UART1, AUX mini uart - *AUX_MU_IER = 0; - *AUX_MU_CNTL = 0; - *AUX_MU_LCR = 3; // 8 bits - *AUX_MU_MCR = 0; - *AUX_MU_IER = 0; - *AUX_MU_IIR = 0xc6; // disable interrupts - *AUX_MU_BAUD = 270; // 115200 baud - /* map UART1 to GPIO pins */ - r=*GPFSEL1; - r&=~((7<<12)|(7<<15)); // gpio14, gpio15 - r|=(2<<12)|(2<<15); // alt5 - *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 - *AUX_MU_CNTL = 3; // enable Tx, Rx -} - -/** - * Send a character - */ -void uart_send(unsigned int c) { - /* wait until we can send */ - do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x20)); - /* write the character to the buffer */ - *AUX_MU_IO=c; -} - -/** - * Receive a character - */ -char uart_getc() { - char r; - /* wait until something is in the buffer */ - do{asm volatile("nop");}while(!(*AUX_MU_LSR&0x01)); - /* read it and return */ - r=(char)(*AUX_MU_IO); - /* 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/.04_mailboxes/uart.h b/.04_mailboxes/uart.h deleted file mode 100644 index 99b2be48..00000000 --- a/.04_mailboxes/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/04_mailboxes/Cargo.lock b/04_mailboxes/Cargo.lock new file mode 100644 index 00000000..6423a007 --- /dev/null +++ b/04_mailboxes/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/04_mailboxes/Cargo.toml b/04_mailboxes/Cargo.toml new file mode 100644 index 00000000..8e79f96f --- /dev/null +++ b/04_mailboxes/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/04_mailboxes/Makefile b/04_mailboxes/Makefile new file mode 100644 index 00000000..8201c16a --- /dev/null +++ b/04_mailboxes/Makefile @@ -0,0 +1,58 @@ +# +# 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 + +clean: + cargo clean + rm -f kernel8 diff --git a/04_mailboxes/README.md b/04_mailboxes/README.md new file mode 100644 index 00000000..1f8941e7 --- /dev/null +++ b/04_mailboxes/README.md @@ -0,0 +1,73 @@ +# Tutorial 04 - Mailboxes + +Before we could go on with UART0, we need mailboxes. So in this tutorial we +introduce the mailbox interface. We'll use it to query the board's serial +number and print that out on UART1. + +NOTE: qemu does not redirect UART1 to terminal by default, only UART0! + +## uart.rs + +`MiniUart::hex(&self, d: u32)` prints out a binary value in hexadecimal format. + +## mbox.rs + +The mailbox interface. First we fill up the message in the `mbox.buffer` array, +then we call `Mbox::call(&mut self, channel: u32)` to pass it to the GPU, +specifying the mailbox channel. In this example we have used the [property +channel], which requires the message to be formatted as: + +[property channel]: (https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface) + +``` + 0. size of the message in bytes, (x+1)*4 + 1. mbox::REQUEST magic value, indicates request message + 2-x. tags + x+1. mbox::tag::LAST magic value, indicates no more tags +``` + +Where each tag looks like: + +``` + n+0. tag identifier + n+1. value buffer size in bytes + n+2. must be zero + n+3. optional value buffer +``` + +### rlibc + +The mailbox buffer is a fixed array that is zero-initialized. To achieve +zero-initialization, Rust utilizies and links to the `memset()` function, which +is normally provided by `libc`. + +Since we are writing a `no_std` crate, we need to explicitly provide it. The +easiest way is pulling in [rlibc] by adding it as an `extern crate` to `main.rs` +and adding the dependency to `Cargo.toml`. + +[rlibc]: https://github.com/alexcrichton/rlibc + +### Synchronization + +When signaling the GPU about a new mailbox message, we need to take care that +mailbox buffer setup has really finished. Both setting up mailbox contents and +signaling the GPU is done with store operations to memory (RAM and MMIO). There +is an unlikely chance that the compiler reorders instructions, resulting in +signaling the GPU _before_ all of the contents have been written to the mailbox +buffer. We prevent this by inserting a [compiler fence]. + +Please note that such reordering might also be done by CPUs that feature +[out-of-order execution]. Lucky us, although the Rasperry Pi 3 features +`ARMv8.0-A` CPU cores, the `Cortex-A53` variant is used, [which does not support +this feature]. Otherwise, a [fence] that additionally [emits corresponding CPU +instructions] to prevent this behavior would be needed. + +[compiler fence]: https://doc.rust-lang.org/beta/core/sync/atomic/fn.compiler_fence.html +[out-of-order execution]: https://en.wikipedia.org/wiki/Out-of-order_execution +[which does not support this feature]: https://en.wikipedia.org/wiki/Comparison_of_ARMv8-A_cores +[fence]: https://doc.rust-lang.org/std/sync/atomic/fn.fence.html +[emits corresponding CPU instructions]: https://developer.arm.com/products/architecture/a-profile/docs/100941/latest/barriers + +## Main + +We query the board's serial number and then we display it on the serial console. diff --git a/04_mailboxes/aarch64-raspi3-none-elf.json b/04_mailboxes/aarch64-raspi3-none-elf.json new file mode 100644 index 00000000..407f21b8 --- /dev/null +++ b/04_mailboxes/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/04_mailboxes/dockcross-linux-aarch64 b/04_mailboxes/dockcross-linux-aarch64 new file mode 100755 index 00000000..3c7481d2 --- /dev/null +++ b/04_mailboxes/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/04_mailboxes/kernel8.img b/04_mailboxes/kernel8.img new file mode 100755 index 0000000000000000000000000000000000000000..97285b1dfa81ca4f5b28a9750e5243c3a44da51a GIT binary patch literal 1920 zcma)-UrbY19LImRx1_hFOz27kSJHNg3oW!}B|=#wTx2c?VzkuAgBjL^rAVnONa7+% z+xY@kaCK%TdqLcTu|$0F!TYcbG)r`BCg#SyZ7JKb6ss8GGU-gY`<~kp-Lg$@a&vz7 z_vicjoYQkoXUKcst`*M(h_3h9`1^{YY@Q+NZ6!+1a&-O~zOC>R3B;bArF6ZPG>LjG zC9iNXUngD{%{R~1kjbT4Yg*!ssi=b@7fZ+=ZF@H|uP48e#N6ZoQJSRMCZ@&g@0D$h zi8hj2Nyye~<6kW06@NRCd72Zl7d7OctQ5UhE6K$4LKS3+#`(xq^f-kWtC`o5-)$DX zcad`!{^$Z9S*$K|-h!XS3H@D&GmW>P`-rzXmw4fCS~t;iw%X`qyfc3){!(y;z;>p{ z$?WgIIRMUo^B;YY|Ec1C9eq}ceO_exn(uEF=pw>>MS1DSWS-+OwJ#vqHfI6@O1@6mf`P=C$?-bmm_NUGRMpV8l_C@Ii7koZ{0xYHi(EZ&Roz48o=4E@LcZ&eS` zYmH2c*|!y?DTDbKxEhbsPLc-un#EYI6Y-Stw8_C?Zq-aHqFC%x_a`>QTe) zi!9FX5!{n~W3(D1@@IH!%7=R86y58{oIGbUa(ne6B_H5EO6y`R*-|n0kk_X=|S{eH7m%SLryqQ<>rg`x21s+$Nl64%@ z2+EIjV$NO3>|WWeGJ!?a?~vUktY1(*3kJ8!(_7TvCr=@V@wrvD0t;hut4t?~^D8hh z7N%W?nq|H$brvIs`_js3vRJ$1Jl1kI35x;=2}cR7a+Ty|d!L=njeRai?K#I+?K$kl z>`mmey{~@nq8rS23;FAttZQlfCOEGtBlgg`u5Arhtr>6eUyfOY$5tG*#Hq24{!r+c z%{Mx7Jn%t(AZ#~ue{37+A07yVY~j(NBmKj+fsuD?h6CZikx;+w_%T~#w10Rb#crUO K4y1TC#=ig_UY=qA literal 0 HcmV?d00001 diff --git a/.04_mailboxes/link.ld b/04_mailboxes/link.ld similarity index 100% rename from .04_mailboxes/link.ld rename to 04_mailboxes/link.ld diff --git a/04_mailboxes/raspi3_glue/Cargo.toml b/04_mailboxes/raspi3_glue/Cargo.toml new file mode 100644 index 00000000..99c8e683 --- /dev/null +++ b/04_mailboxes/raspi3_glue/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "raspi3_glue" +version = "0.1.0" +authors = ["Andre Richter "] + +[dependencies] diff --git a/.04_mailboxes/start.S b/04_mailboxes/raspi3_glue/src/boot_cores.S similarity index 84% rename from .04_mailboxes/start.S rename to 04_mailboxes/raspi3_glue/src/boot_cores.S index 27d0c503..f6f28af6 100644 --- a/.04_mailboxes/start.S +++ b/04_mailboxes/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/04_mailboxes/raspi3_glue/src/lib.rs b/04_mailboxes/raspi3_glue/src/lib.rs new file mode 100644 index 00000000..e1d22891 --- /dev/null +++ b/04_mailboxes/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/04_mailboxes/src/gpio.rs b/04_mailboxes/src/gpio.rs new file mode 100644 index 00000000..03914da2 --- /dev/null +++ b/04_mailboxes/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 + 0x00200004) as *const RW; +pub const GPPUD: *const RW = (MMIO_BASE + 0x00200094) as *const RW; +pub const GPPUDCLK0: *const RW = (MMIO_BASE + 0x00200098) as *const RW; diff --git a/04_mailboxes/src/main.rs b/04_mailboxes/src/main.rs new file mode 100644 index 00000000..f20cae78 --- /dev/null +++ b/04_mailboxes/src/main.rs @@ -0,0 +1,84 @@ +/* + * 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 = 0x3F000000; + +mod mbox; +mod gpio; +mod uart; + +use core::sync::atomic::{compiler_fence, Ordering}; + +fn main() { + let mut mbox = mbox::Mbox::new(); + let uart = uart::MiniUart::new(); + + // set up serial console + uart.init(); + + // get the board's unique serial number with a mailbox call + mbox.buffer[0] = 8 * 4; // length of the message + mbox.buffer[1] = mbox::REQUEST; // this is a request message + mbox.buffer[2] = mbox::tag::GETSERIAL; // get serial number command + mbox.buffer[3] = 8; // buffer size + mbox.buffer[4] = 8; + mbox.buffer[5] = 0; // clear output buffer + mbox.buffer[6] = 0; + mbox.buffer[7] = 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); + + // send the message to the GPU and receive answer + let serial_avail = match mbox.call(mbox::channel::PROP) { + Err(_) => false, + Ok(()) => true, + }; + + uart.getc(); // Press a key first before being greeted + uart.puts("Hello Rustacean!\n"); + + if serial_avail { + uart.puts("My serial number is: "); + uart.hex(mbox.buffer[6]); + uart.hex(mbox.buffer[5]); + uart.puts("\n"); + } else { + uart.puts("Unable to query serial!\n"); + } + + // echo everything back + loop { + uart.send(uart.getc()); + } +} diff --git a/04_mailboxes/src/mbox.rs b/04_mailboxes/src/mbox.rs new file mode 100644 index 00000000..9f5845cb --- /dev/null +++ b/04_mailboxes/src/mbox.rs @@ -0,0 +1,134 @@ +/* + * 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 GETSERIAL: u32 = 0x10004; + pub const LAST: u32 = 0; +} + +// Responses +mod response { + pub const SUCCESS: u32 = 0x80000000; + pub const ERROR: u32 = 0x80000001; // error parsing request buffer (partial response) +} + +pub const REQUEST: u32 = 0; +const FULL: u32 = 0x80000000; +const EMPTY: u32 = 0x40000000; + +// 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/04_mailboxes/src/uart.rs b/04_mailboxes/src/uart.rs new file mode 100644 index 00000000..31b24c8d --- /dev/null +++ b/04_mailboxes/src/uart.rs @@ -0,0 +1,169 @@ +/* + * 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 gpio; + +const MINI_UART_BASE: u32 = MMIO_BASE + 0x215000; + +/// Auxilary mini UART registers +#[allow(non_snake_case)] +#[repr(C, packed)] +struct Registers { + _reserved0: u32, // 0x00 + ENABLES: RW, // 0x04 + _reserved1: [u8; 0x38], // 0x08 + MU_IO: RW, // 0x40 + MU_IER: RW, // 0x44 + MU_IIR: RW, // 0x48 + MU_LCR: RW, // 0x4C + MU_MCR: RW, // 0x50 + MU_LSR: RW, // 0x54 + MU_MSR: RW, // 0x58 + MU_SCRATCH: RW, // 0x5C + MU_CNTL: RW, // 0x60 + MU_STAT: RW, // 0x64 + MU_BAUD: RW, // 0x68 +} + +pub struct MiniUart { + registers: *const Registers, +} + +impl MiniUart { + pub fn new() -> MiniUart { + MiniUart { + registers: MINI_UART_BASE as *const Registers, + } + } + + ///Set baud rate and characteristics (115200 8N1) and map to GPIO + pub fn init(&self) { + // initialize UART + unsafe { + (*self.registers).ENABLES.modify(|x| x | 1); // enable UART1, AUX mini uart + (*self.registers).MU_IER.write(0); + (*self.registers).MU_CNTL.write(0); + (*self.registers).MU_LCR.write(3); // 8 bits + (*self.registers).MU_MCR.write(0); + (*self.registers).MU_IER.write(0); + (*self.registers).MU_IIR.write(0xC6); // disable interrupts + (*self.registers).MU_BAUD.write(270); // 115200 baud + + // map UART1 to GPIO pins + (*gpio::GPFSEL1).modify(|x| { + // Modify with a closure + let mut ret = x; + ret &= !((7 << 12) | (7 << 15)); // gpio14, gpio15 + ret |= (2 << 12) | (2 << 15); // alt5 + + 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); // flush GPIO setup + (*self.registers).MU_CNTL.write(3); // enable Tx, Rx + } + } + + /// Send a character + pub fn send(&self, c: char) { + unsafe { + // wait until we can send + loop { + if ((*self.registers).MU_LSR.read() & 0x20) == 0x20 { + break; + } + asm!("nop" :::: "volatile"); + } + + // write the character to the buffer + (*self.registers).MU_IO.write(c as u32); + } + } + + /// Receive a character + pub fn getc(&self) -> char { + unsafe { + // wait until something is in the buffer + loop { + if ((*self.registers).MU_LSR.read() & 0x01) == 0x01 { + break; + } + asm!("nop" :::: "volatile"); + } + } + + // read it and return + let mut ret = unsafe { (*self.registers).MU_IO.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); + } + } +}