diff --git a/04_mailboxes/main.c b/04_mailboxes/main.c index 44fdda6e..4af4d252 100644 --- a/04_mailboxes/main.c +++ b/04_mailboxes/main.c @@ -31,7 +31,7 @@ void main() // set up serial console uart_init(); - // get the command line with a mailbox call + // 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 diff --git a/05_uart0/main.c b/05_uart0/main.c index 44fdda6e..4af4d252 100644 --- a/05_uart0/main.c +++ b/05_uart0/main.c @@ -31,7 +31,7 @@ void main() // set up serial console uart_init(); - // get the command line with a mailbox call + // 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 diff --git a/0A_pcscreenfont/OLVASSEL.md b/0A_pcscreenfont/OLVASSEL.md index 606fe6c3..232f6b1d 100644 --- a/0A_pcscreenfont/OLVASSEL.md +++ b/0A_pcscreenfont/OLVASSEL.md @@ -24,7 +24,15 @@ Makefile -------- Egy új object-et adtam hozzá, ami a psf-ből generálódik. Jó példa arra, hogyan kell bináris fájlt behúzni és -hivatkozni C forrásból. +hivatkozni C forrásból. A következő parancsot használtam a cimke nevének kiderítésére: + +```sh +$ aarch64-elf-readelf -s font.o + ... kimenet törölve az átláthatóság miatt ... + 2: 0000000000000820 0 NOTYPE GLOBAL DEFAULT 1 _binary_font_psf_end + 3: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 1 _binary_font_psf_start + 4: 0000000000000820 0 NOTYPE GLOBAL DEFAULT ABS _binary_font_psf_size +``` Main ---- diff --git a/0A_pcscreenfont/README.md b/0A_pcscreenfont/README.md index e71b86c2..8cf01bb2 100644 --- a/0A_pcscreenfont/README.md +++ b/0A_pcscreenfont/README.md @@ -23,7 +23,15 @@ Makefile -------- I've added a new object file, generated from the psf. It's a good example of how to include and reference -a binary file in C. +a binary file in C. I've used the following command to find out the label: + +```sh +$ aarch64-elf-readelf -s font.o + ... output removed for clearity ... + 2: 0000000000000820 0 NOTYPE GLOBAL DEFAULT 1 _binary_font_psf_end + 3: 0000000000000000 0 NOTYPE GLOBAL DEFAULT 1 _binary_font_psf_start + 4: 0000000000000820 0 NOTYPE GLOBAL DEFAULT ABS _binary_font_psf_size +``` Main ---- diff --git a/0E_initrd/Makefile b/0E_initrd/Makefile new file mode 100644 index 00000000..63a165bc --- /dev/null +++ b/0E_initrd/Makefile @@ -0,0 +1,47 @@ +# +# 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 $@ + +tar.o: + tar -cf initrd.tar *.md *.c *.h + aarch64-elf-ld -r -b binary -o tar.o initrd.tar + +kernel8.img: start.o tar.o $(OBJS) + aarch64-elf-ld -nostdlib -nostartfiles start.o tar.o $(OBJS) -T link.ld -o kernel8.elf + aarch64-elf-objcopy -O binary kernel8.elf kernel8.img + +clean: + rm kernel8.elf *.o *.tar >/dev/null 2>/dev/null || true diff --git a/0E_initrd/OLVASSEL.md b/0E_initrd/OLVASSEL.md new file mode 100644 index 00000000..f6380f08 --- /dev/null +++ b/0E_initrd/OLVASSEL.md @@ -0,0 +1,49 @@ +Tutorial 0E - Kezdeti memória lemez +=================================== + +Sok OS használ kezdeti memória lemezt (initrd) hogy fájlokat töltsön be induláskor. Szükségét éreztem egy +ilyen oktatóanyagnak, mivel a legtöbb hobby OS fejlesztőnek fingja sincs, hogy kell ezt rendesen csinálni. + +Először is, nem fogjuk újra feltalálni a spanyol viaszt és kiagyalni egy új formátumot, amihez aztán egy +szörnyű kreátor programot heggesztünk. Helyette a POSIX szabvány `tar` archíválót fogjuk használni. A formátuma +pofonegyszerű, először jön egy 512 bájtos fejléc a fájl adataival, majd ezt követi a fájl tartalma nullákkal +kiegészítve, hogy a hossza 512-vel osztható legyen. Ez ismétlődik minden egyes fájlra az archívban. +Ha szeretnél tömörített initrd-t, akkor javaslom például a [tinf](https://bitbucket.org/jibsen/tinf) könyvtárat +a kicsomagoláshoz. A kitömörített adatot az itt ismertetett módszerrel olvashatod. + +Másodszor, a betöltéshez több lehetőségünk is van: + +### Betöltjük a fájlt saját magunk +Ehhez használhatod a `fat_readfile()` funkciót az előző oktatóanyagból. Ebben az esetben az initrd címét visszaadja +a függvény. + +### Megkéred a GPU-t hogy töltse be neked +Aztán használhatod a `config.txt`-t hogy utasítsd a start.elf-et az initrd betöltésére. Ez azért jó, mert ehhez +nem kell SD kártya olvasó és FAT értelmező, így a kerneled jóval kissebb lesz. Ami a +[config.txt](https://www.raspberry.org/documentation/configuration/config-txt/boot.md) parancsait illeti, +két lehetőséged is van: + +`initramfs (fájlnév) followkernel` - ez betölti a (fájlnév) nevű fájlt mindjárt a kerneled után. Az initrd-d kezdőcíme +ekkor a *&_end* cimke lesz, amit a linker szkriptben definiáltunk. + +`initramfs (fájlnév) (cím)` - a megadott címre tölti be a (fájlnév) nevű fájlt. A kezdőcíme ekkor *(cím)* lesz. + +### Statikus linkelés +Nem túl praktikus, mivel mindig újra kell fordítani a kernelt, ha változtatni akarsz az initrd tartalmán. Azonban +ez a legegyszerűbb módszer, és hogy átlátható legyen az oktatóanyag, ezért ezt választottam. Az initrd-d kezdőcímét +ez esetben a *_binary_initrd_tar_start* cimke szolgáltatja. + +Makefile +-------- +Hozzáadtam egy tar.o létrehozó szabályt a Makefile-hoz. Ez dinamikusan legenerálja a tar-t, majd object fájllá +konvertálja. + +Initrd.h, initrd.c +------------------ + +`initrd_list(buf)` kilistázza a bufferben lévő tar archív tartalmát. + +Main +---- + +Inicializáljuk a konzolt, majd átadjuk az initrd kezdőcímét a listázónak. diff --git a/0E_initrd/README.md b/0E_initrd/README.md new file mode 100644 index 00000000..ffc95a14 --- /dev/null +++ b/0E_initrd/README.md @@ -0,0 +1,49 @@ +Tutorial 0E - Initial RamDisk +============================= + +Many OS uses initial ramdisk to load files into memory during boot. I felt the need for such +a tutorial as most hobby OS developer's never learned how to do this porperly. + +First of all, we're not going to reinvent the wheel a come up with a new format and an awful +image creator tool. We're going to use the POSIX standard `tar` utility to create our initrd. It's format +is really simple, first comes an 512 bytes long header with file meta information, followed by the +file contents padded with zeros to round up to multiple of 512 bytes. This repeats for every file in the archive. +If you want a compressed initrd, you can use for example the [tinf](https://bitbucket.org/jibsen/tinf) library to +deflate. The uncompressed buffer can be parsed by the method described here. + +Second, about loading it into memory, we have several options: + +### Load a file on our own +You can use the `fat_readfile()` from the previous tutorial. In that case your initrd's address +will be returned by the function. + +### Ask the GPU to do so +You can use `config.txt` to tell start.elf to load the initrd for you. With this you won't need +any SD card reader or FAT parser at all, resulting in a much smaller kernel. As for the +[config.txt](https://www.raspberry.org/documentation/configuration/config-txt/boot.md), +you have two options: + +`initramfs (filename) followkernel` - this will load (filename) after your kernel. You can access it at the label +*&_end* defined by our linker script. + +`initramfs (filename) (address)` - load (filename) into a specified location. You can access it at *(address)*. + +### Statically link +This is not very practical because you have to build your kernel every time you want to change the initrd. But +it is the simplest method, and to keep this tutorial simple we'll use this. You can access the initrd by the label +*_binary_initrd_tar_start*. + +Makefile +-------- +I've added a tar.o to the usual Makefile. This rule will dinamically create a tar file and convert it into an +object file. + +Initrd.h, initrd.c +------------------ + +`initrd_list(buf)` list the contents of a tar archive in the buffer. + +Main +---- + +We initialize console and the pass the initrd buffer to lister. diff --git a/0E_initrd/delays.c b/0E_initrd/delays.c new file mode 100644 index 00000000..aba77264 --- /dev/null +++ b/0E_initrd/delays.c @@ -0,0 +1,81 @@ +/* + * 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 SYSTMR_LO ((volatile unsigned int*)(MMIO_BASE+0x00003004)) +#define SYSTMR_HI ((volatile unsigned int*)(MMIO_BASE+0x00003008)) + +/** + * Wait N CPU cycles (ARM CPU only) + */ +void wait_cycles(unsigned int n) +{ + if(n) while(n--) { asm volatile("nop"); } +} + +/** + * Wait N microsec (ARM CPU only) + */ +void wait_msec(unsigned int n) +{ + register unsigned long f, t, r; + // get the current counter frequency + asm volatile ("mrs %0, cntfrq_el0" : "=r"(f)); + // read the current counter + asm volatile ("mrs %0, cntpct_el0" : "=r"(t)); + // calculate expire value for counter + t+=((f/1000)*n)/1000; + do{asm volatile ("mrs %0, cntpct_el0" : "=r"(r));}while(r0) { + r<<=3; + r+=*s++-'0'; + } + return r; +} + +/** + * List the contents of a tar archive + */ +void initrd_list(char *buf) +{ + uart_puts("Offset Size Access rights\t\tFilename\n"); + // iterate on archive's contents + while(!__builtin_memcmp(buf+257,"ustar",5)){ + int fs=oct2bin(buf+0x7c,11); + // print out meta information + uart_hex((unsigned int)((unsigned long)buf)+512); + uart_send(' '); + uart_hex(fs); // file size in hex + uart_send(' '); + uart_puts(buf+0x64); // access bits in octal + uart_send(' '); + uart_puts(buf+0x109); // owner + uart_send('.'); + uart_puts(buf+0x129); // group + uart_send('\t'); + uart_puts(buf); // filename + uart_puts("\n"); + // jump to the next file + buf+=(((fs+511)/512)+1)*512; + } +} diff --git a/0E_initrd/initrd.h b/0E_initrd/initrd.h new file mode 100644 index 00000000..fa90a7b3 --- /dev/null +++ b/0E_initrd/initrd.h @@ -0,0 +1,26 @@ +/* + * 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 initrd_list(char *buf); diff --git a/0E_initrd/kernel8.img b/0E_initrd/kernel8.img new file mode 100755 index 00000000..91d164e9 Binary files /dev/null and b/0E_initrd/kernel8.img differ diff --git a/0E_initrd/link.ld b/0E_initrd/link.ld new file mode 100644 index 00000000..1352bfb1 --- /dev/null +++ b/0E_initrd/link.ld @@ -0,0 +1,44 @@ +/* + * 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. + * + */ + +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; diff --git a/0E_initrd/main.c b/0E_initrd/main.c new file mode 100644 index 00000000..85d607bc --- /dev/null +++ b/0E_initrd/main.c @@ -0,0 +1,44 @@ +/* + * 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 "initrd.h" + +// import our bitchunk from tar.o +extern volatile unsigned char _binary_initrd_tar_start; + +void main() +{ + // set up serial console + uart_init(); + + // list contents of an archive + initrd_list((char*)&_binary_initrd_tar_start); + + // echo everything back + while(1) { + uart_send(uart_getc()); + } +} diff --git a/0E_initrd/mbox.c b/0E_initrd/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/0E_initrd/mbox.c @@ -0,0 +1,63 @@ +/* + * 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/0E_initrd/mbox.h b/0E_initrd/mbox.h new file mode 100644 index 00000000..8408d275 --- /dev/null +++ b/0E_initrd/mbox.h @@ -0,0 +1,47 @@ +/* + * 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_SETPOWER 0x28001 +#define MBOX_TAG_SETCLKRATE 0x38002 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); diff --git a/0E_initrd/start.S b/0E_initrd/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/0E_initrd/start.S @@ -0,0 +1,55 @@ +/* + * 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. + * + */ + +.section ".text.boot" + +.global _start + +_start: + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // cpu id > 0, stop +1: wfe + b 1b +2: // cpu id == 0 + + // set stack before our code + ldr x1, =_start + 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 + // for failsafe, halt this core too + b 1b diff --git a/0E_initrd/uart.c b/0E_initrd/uart.c new file mode 100644 index 00000000..d0d9a6fd --- /dev/null +++ b/0E_initrd/uart.c @@ -0,0 +1,153 @@ +/* + * 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" +#include "delays.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|=(2<<12)|(2<<15); // alt5 + *GPFSEL1 = r; + *GPPUD = 0; // enable pins 14 and 15 + wait_cycles(150); + *GPPUDCLK0 = (1<<14)|(1<<15); + wait_cycles(150); + *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); + } +} + +/** + * Dump memory + */ +void uart_dump(void *ptr) +{ + unsigned long a,b,d; + unsigned char c; + for(a=(unsigned long)ptr;a<(unsigned long)ptr+512;a+=16) { + uart_hex(a); uart_puts(": "); + for(b=0;b<16;b++) { + c=*((unsigned char*)(a+b)); + d=(unsigned int)c;d>>=4;d&=0xF;d+=d>9?0x37:0x30;uart_send(d); + d=(unsigned int)c;d&=0xF;d+=d>9?0x37:0x30;uart_send(d); + uart_send(' '); + if(b%4==3) + uart_send(' '); + } + for(b=0;b<16;b++) { + c=*((unsigned char*)(a+b)); + uart_send(c<32||c>=127?'.':c); + } + uart_send('\r'); + uart_send('\n'); + } +} diff --git a/0E_initrd/uart.h b/0E_initrd/uart.h new file mode 100644 index 00000000..f74e5263 --- /dev/null +++ b/0E_initrd/uart.h @@ -0,0 +1,31 @@ +/* + * 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); +void uart_dump(void *ptr); diff --git a/0F_executionlevel/Makefile b/0F_executionlevel/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/0F_executionlevel/Makefile @@ -0,0 +1,43 @@ +# +# 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/0F_executionlevel/OLVASSEL.md b/0F_executionlevel/OLVASSEL.md new file mode 100644 index 00000000..e7b830e7 --- /dev/null +++ b/0F_executionlevel/OLVASSEL.md @@ -0,0 +1,26 @@ +Tutorial 0F - Futási szintek +============================ + +Mielőtt rátérhetnénk a virtuális memóriára, beszélnünk kell a futási szintekről. Minden szintnek saját +lapfordító tára van, emiatt életbevágó, hogy tudjuk, melyik szinten futunk éppen. Ezért ebben az oktatóanyagban +megbizonyosodunk róla, hogy rendszerfelügyeleti szinten (supervisor) azaz EL1-en vagyunk-e. Qemu alatt a gép +indulhat egyből EL1-en, az igazi Raspberry Pi vason azonban mindig virtualizációs szinten (hypervisor) azaz EL2-n +ébredünk. Qemu alatt a szintváltást a "-d int" kapcsolóval debuggolhatjuk. + +```sh +$ qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial stdio -d int +Exception return from AArch64 EL2 to AArch64 EL1 PC 0x8004c +Current EL is: 00000001 +``` + +Start +----- + +Hozzáadtam egy pár Assembly sort, ami átállítja a futási szintet, ha nem rendszerfelügyeleti szinten lennénk. +De mielőtt ezt megtehetnénk, hozzáférést kell biztosítani a számláló regiszterekhez (counter, amit a wait_msec() +használ). Végezetül egy kivételkezelőből való visszatérést hazudunk, hogy ténylegesen szintet váltsunk. + +Main +---- + +Lekérjük az aktuális futási szintet, és kiírjuk a soros konzolra. diff --git a/0F_executionlevel/README.md b/0F_executionlevel/README.md new file mode 100644 index 00000000..076bef23 --- /dev/null +++ b/0F_executionlevel/README.md @@ -0,0 +1,25 @@ +Tutorial 0F - Execution levels +============================== + +Before we can go on to virtual memory, we have to talk about execution levels. Each level has it's own +memory translation tables, therefore it's cruital to know which one we are using. So in this tutorial we're +make sure of it, we are at supervisor level, EL1. Qemu may start machine at EL1, but real Raspberry Pi hardware +always boots at hypervisor level, EL2. Under qemu use "-d int" to debug the level change. + +```sh +$ qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial stdio -d int +Exception return from AArch64 EL2 to AArch64 EL1 PC 0x8004c +Current EL is: 00000001 +``` + +Start +----- + +I've added a little bit more Assembly code for changing the execution level if we're not at supervisor level. +But before we can do that, we have to grant access for the counter registers (used by wait_msec()). +Finally, we fake an exception return to change the level for real. + +Main +---- + +We query the current execution level and then we display it on the serial console. diff --git a/0F_executionlevel/gpio.h b/0F_executionlevel/gpio.h new file mode 100644 index 00000000..52fa671d --- /dev/null +++ b/0F_executionlevel/gpio.h @@ -0,0 +1,45 @@ +/* + * 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/0F_executionlevel/kernel8.img b/0F_executionlevel/kernel8.img new file mode 100755 index 00000000..ff00bfdd Binary files /dev/null and b/0F_executionlevel/kernel8.img differ diff --git a/0F_executionlevel/link.ld b/0F_executionlevel/link.ld new file mode 100644 index 00000000..1352bfb1 --- /dev/null +++ b/0F_executionlevel/link.ld @@ -0,0 +1,44 @@ +/* + * 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. + * + */ + +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; diff --git a/0F_executionlevel/main.c b/0F_executionlevel/main.c new file mode 100644 index 00000000..2e2bad07 --- /dev/null +++ b/0F_executionlevel/main.c @@ -0,0 +1,46 @@ +/* + * 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" + +void main() +{ + unsigned int el; + + // set up serial console + uart_init(); + + // read the current level from system register + asm volatile ("mrs %0, CurrentEL" : "=r" (el)); + + uart_puts("Current EL is: "); + uart_hex(el>>2); + uart_puts("\n"); + + // echo everything back + while(1) { + uart_send(uart_getc()); + } +} diff --git a/0F_executionlevel/mbox.c b/0F_executionlevel/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/0F_executionlevel/mbox.c @@ -0,0 +1,63 @@ +/* + * 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/0F_executionlevel/mbox.h b/0F_executionlevel/mbox.h new file mode 100644 index 00000000..09844dea --- /dev/null +++ b/0F_executionlevel/mbox.h @@ -0,0 +1,47 @@ +/* + * 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_SETCLKRATE 0x38002 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); diff --git a/0F_executionlevel/start.S b/0F_executionlevel/start.S new file mode 100644 index 00000000..34cf99c8 --- /dev/null +++ b/0F_executionlevel/start.S @@ -0,0 +1,73 @@ +/* + * 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. + * + */ + +.section ".text.boot" + +.global _start + +_start: + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // cpu id > 0, stop +1: wfe + b 1b +2: // cpu id == 0 + + // set stack before our code + ldr x1, =_start + + // set up EL1 + mrs x0, CurrentEL + cmp x0, #4 + beq 5f + msr sp_el1, x1 + // enable CNTP for EL1 + mrs x0, cnthctl_el2 + orr x0, x0, #3 + msr cnthctl_el2, x0 + msr cntvoff_el2, xzr + // change execution level to EL1 + mov x2, #0x3c4 + msr spsr_el2, x2 + adr x2, 5f + msr elr_el2, x2 + eret + +5: 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 + // for failsafe, halt this core too + b 1b diff --git a/0F_executionlevel/uart.c b/0F_executionlevel/uart.c new file mode 100644 index 00000000..d368d399 --- /dev/null +++ b/0F_executionlevel/uart.c @@ -0,0 +1,126 @@ +/* + * 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|=(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 + + *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/0F_executionlevel/uart.h b/0F_executionlevel/uart.h new file mode 100644 index 00000000..99b2be48 --- /dev/null +++ b/0F_executionlevel/uart.h @@ -0,0 +1,30 @@ +/* + * 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/10_virtualmemory/Makefile b/10_virtualmemory/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/10_virtualmemory/Makefile @@ -0,0 +1,43 @@ +# +# 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/10_virtualmemory/OLVASSEL.md b/10_virtualmemory/OLVASSEL.md new file mode 100644 index 00000000..edcd12e2 --- /dev/null +++ b/10_virtualmemory/OLVASSEL.md @@ -0,0 +1,49 @@ +Tutorial 10 - Virtuális Memória +=============================== + +Elérkeztünk a legegyszerűbb és egyben legbonyolultabb oktatóanyagunkhoz. Egyszerű, mert nem csinálunk mást, mint +feltöltünk egy tömböt, aztán beállítunk pár regisztert. A nehézség abban rejlik, hogy mi kerüljön a tömbbe. + +Feltételezem kellő ismerettel rendelkezel az AMD64-es lapozásáról. Ha nem, akkor erősen javaslom, hogy szánj rá +időt mielőtt folytatnád. Az ARMv8 MMU-ja sokkal de sokkal bonyolultabb és összetettebb, mint az AMD64-é. Határozottan +nem jó ötlet ezzel kezdeni. + +Az AMD64 címfordítása roppant egyszerű, egy táblacím regisztere van, a memóriát 4k-s lapokra osztja, 4 szinten, +és csak egyféle luk van definilálva a címtérben. ARMv8 ennél sokkal combosabb. Beállíthatot a lapkeret méretét, +a lapozási szintek számát, összefűzheted a lapfordító táblázatokat egy adott szinten, de még a luk méretét is +beállíthatod. Képtelenség mindezt egy oktatóanyaggal lefedni. Ezért úgy döntöttem, inkább úgy állítom be az ARMv8 +MMU-ját, hogy minnél jobban hasonlítson az AMD64-éhez. Ez a következőket jelenti: 4k-s lapméretet fogunk használni, +2M-es blokkmérettel és 512G-s címterülettel (3 szint), ahol a 4. szintet két regiszter helyettesíti. Fogd fel +úgy, hogy amíg AMD64-n a 4. szintű laptábla címe a CR3-ban van megadva, addig ARMv8-on van egyszer a TTBR0 regiszter, +ami ennek a táblának az első elemét tartalmazza, valamint van a TTBR1 regiszter, ami meg az utolsó, 512. elemét, +ezért nincs szükség 4. szintű laptáblára. Minden köztes cím (amit a 2.-511. elemek fordítanának) a lukra esik, más +szavakkal azok nem kanonikus memória címek. + + +A lapfordító táblázat egyébként ugyanúgy néz ki: 64 bites elemeket tartalmaz, amikben van egy fizikai cím és néhány +attribútum bit, minden egyes szinten. De ARMv8-on sokkal több lehetőséged van. Külön beállíthatod a gyorsítótárat +(cachability), megosztást (shareability) és a hozzáférést is. Ezen kívül van még egy memória típus tömböt tartalmazó +regiszter, aminek az elemeire indexelnek a lapcím fordító tábla bejegyzéseinek bitjei. + +A következőképp fogjuk leképezni a virtuális memóriát: az alacsony címeket egy-az-egyben megfeleltetéssel 2M +blokkonként, kivéve az első blokkot, amit 4k-nként. A magas címekre pedig, -2M-nél leképezzük az UART0 MMIO-ját. + +Mmu.h, mmu.c +------------ + +`mmu_init()` inicializálja a memória címfordító egységet (Memory Management Unit) + +Start +----- + +Ezúttal hozzáférést kell biztosítanunk a rendszer kontroll regiszterhez is (system control register). + +Link.ld +------- + +Most szükség van arra, hogy az adatterületet és a programunk vége cimkét laphatárra igazítsuk. + +Main +---- + +Beállítjuk a címfordítást, majd kiírunk a konzolra mind egy-az-egyben lapozást, mind magas című lapozást használva. diff --git a/10_virtualmemory/README.md b/10_virtualmemory/README.md new file mode 100644 index 00000000..25bd9ac8 --- /dev/null +++ b/10_virtualmemory/README.md @@ -0,0 +1,48 @@ +Tutorial 10 - Virtual Memory +============================ + +We came to the simplest and most difficult tutorial at the same time. It's simple as all we are going to do +is fill up an array, and set some registers. The difficulty lies in knowing what values should we put in that array. + +I assume you have a fair knowledge about page translation mechanism on AMD64. If not, I strongly suggest to +do some tutorial on it before you continue. ARMv8's MMU is much much more complex and featureful than it's AMD64 +counterpart. It is definitely not good to start with. + +As AMD64's address translation is very simple, it has one paging table register, it splits memory into 4k +pages only with 4 levels, and it has one well defined hole in the address space. ARMv8 is much more powerful. You +can set the size of the pageframe, the number of translation levels, you can concatenate translation tables for a +given level, and you can even configure the hole's size. It is impossible to cover all of these in one tutorial. +Therefore what I'm going to do is configuring ARMv8 MMU to be similar to AMD64's as much as possible. That is: +we're going to use 4k pageframes with 2M blocks and 512G address space (3 levels) with the 4th level in two registers. +Think of it this way: on AMD64 you would have a 4th level table, pointed by CR3. On ARMv8, we have TTBR0 register which +holds the first entry of that 4th level table, and TTBR1 which holds the last, 512th entry of the table, therefore we +don't need the 4th level table at all. Everything between (memory mapped by the 2nd-511th entries) is in the hole, with +other words they are non-canonical addresses. + +The page translation table looks the same: we have 64 bit entries with a physical address and attribute bits in it +at each level. But in ARMv8 you have far more options. You can set cacheability, shareability and accessibility as +well. You also have a special register holding a page attribute array, and you index that with bits in the page +translation attributes. + +We are going to translate virtual address space as follows: lower half will be identity mapped in 2M blocks, except +the first block which will be mapped by 4k frames. In the higher half, at -2M we will map the MMIO of UART0. + +Mmu.h, mmu.c +------------ + +`mmu_init()` function to initialize Memory Management Unit. + +Start +----- + +This time we also have to grant access to the system control register. + +Link.ld +------- + +This time we need page alignment for the data and the end label. + +Main +---- + +We set up page translations, and then we print to the console with both identity mapped and higher half mapped MMIO. diff --git a/10_virtualmemory/gpio.h b/10_virtualmemory/gpio.h new file mode 100644 index 00000000..52fa671d --- /dev/null +++ b/10_virtualmemory/gpio.h @@ -0,0 +1,45 @@ +/* + * 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/10_virtualmemory/kernel8.img b/10_virtualmemory/kernel8.img new file mode 100755 index 00000000..f49d53a4 Binary files /dev/null and b/10_virtualmemory/kernel8.img differ diff --git a/10_virtualmemory/link.ld b/10_virtualmemory/link.ld new file mode 100644 index 00000000..bfddd76f --- /dev/null +++ b/10_virtualmemory/link.ld @@ -0,0 +1,46 @@ +/* + * 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. + * + */ + +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + . = ALIGN(4096); + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + . = ALIGN(4096); + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; diff --git a/10_virtualmemory/main.c b/10_virtualmemory/main.c new file mode 100644 index 00000000..1dfbe077 --- /dev/null +++ b/10_virtualmemory/main.c @@ -0,0 +1,57 @@ +/* + * 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 "mmu.h" + +#define KERNEL_UART0_DR ((volatile unsigned int*)0xFFFFFFFFFFE00000) +#define KERNEL_UART0_FR ((volatile unsigned int*)0xFFFFFFFFFFE00018) + +void main() +{ + char *s="Writing through MMIO mapped in higher half!\r\n"; + + // set up serial console + uart_init(); + + // set up paging + mmu_init(); + + // test mapping + uart_puts("Writing through identity mapped MMIO.\n"); + + // test mapping + while(*s) { + /* wait until we can send */ + do{asm volatile("nop");}while(*KERNEL_UART0_FR&0x20); + /* write the character to the buffer */ + *KERNEL_UART0_DR=*s++; + } + + // echo everything back + while(1) { + uart_send(uart_getc()); + } +} diff --git a/10_virtualmemory/mbox.c b/10_virtualmemory/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/10_virtualmemory/mbox.c @@ -0,0 +1,63 @@ +/* + * 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/10_virtualmemory/mbox.h b/10_virtualmemory/mbox.h new file mode 100644 index 00000000..09844dea --- /dev/null +++ b/10_virtualmemory/mbox.h @@ -0,0 +1,47 @@ +/* + * 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_SETCLKRATE 0x38002 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); diff --git a/10_virtualmemory/mmu.c b/10_virtualmemory/mmu.c new file mode 100644 index 00000000..dae1dbb9 --- /dev/null +++ b/10_virtualmemory/mmu.c @@ -0,0 +1,177 @@ +/* + * 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" // get MMIO_BASE +#include "uart.h" + +#define PAGESIZE 4096 + +// granularity +#define PT_PAGE 0b11 // 4k granule +#define PT_BLOCK 0b01 // 2M granule +// accessibility +#define PT_KERNEL (0<<6) // privileged, supervisor EL1 access only +#define PT_USER (1<<6) // unprivileged, EL0 access allowed +#define PT_RW (0<<7) // read-write +#define PT_RO (1<<7) // read-only +#define PT_AF (1<<10) // accessed flag +#define PT_NX (1UL<<54) // no execute +// shareability +#define PT_OSH (2<<8) // outter shareable +#define PT_ISH (3<<8) // inner shareable +// defined in MAIR register +#define PT_MEM (0<<2) // normal memory +#define PT_DEV (1<<2) // device MMIO +#define PT_NC (2<<2) // non-cachable + +#define TTBR_ENABLE 1 + +// get addresses from linker +extern volatile unsigned char _data; +extern volatile unsigned char _end; + +/** + * Set up page translation tables and enable virtual memory + */ +void mmu_init() +{ + unsigned long r, b, *paging=(unsigned long*)&_end; + + /* create MMU translation tables at _end */ + + // TTBR0, identity L1 + paging[0]=(unsigned long)((unsigned char*)&_end+2*PAGESIZE) | // physical address + PT_PAGE | // it has the "Present" flag, which must be set, and we have area in it mapped by pages + PT_AF | // accessed flag. Without this we're going to have a Data Abort exception + PT_USER | // non-privileged + PT_ISH | // inner shareable + PT_MEM; // normal memory + + // identity L2, first 2M block + paging[2*512]=(unsigned long)((unsigned char*)&_end+3*PAGESIZE) | // physical address + PT_PAGE | // we have area in it mapped by pages + PT_AF | // accessed flag + PT_USER | // non-privileged + PT_ISH | // inner shareable + PT_MEM; // normal memory + + // identity L2 2M blocks + b=MMIO_BASE>>21; + // skip 0th, as we're about to map it by L3 + for(r=1;r<512;r++) + paging[2*512+r]=(unsigned long)((r<<21)) | // physical address + PT_BLOCK | // map 2M block + PT_AF | // accessed flag + PT_NX | // no execute + PT_USER | // non-privileged + (r>=b? PT_OSH|PT_DEV : PT_ISH|PT_MEM); // different attributes for device memory + + // identity L3 + for(r=0;r<512;r++) + paging[3*512+r]=(unsigned long)(r*PAGESIZE) | // physical address + PT_PAGE | // map 4k + PT_AF | // accessed flag + PT_USER | // non-privileged + PT_ISH | // inner shareable + ((r<0x80||r>(unsigned long)&_data/PAGESIZE)? PT_RW|PT_NX : PT_RO); // different for code and data + + // TTBR1, kernel L1 + paging[512+511]=(unsigned long)((unsigned char*)&_end+4*PAGESIZE) | // physical address + PT_PAGE | // we have area in it mapped by pages + PT_AF | // accessed flag + PT_KERNEL | // privileged + PT_ISH | // inner shareable + PT_MEM; // normal memory + + // kernel L2 + paging[4*512+511]=(unsigned long)((unsigned char*)&_end+5*PAGESIZE) | // physical address + PT_PAGE | // we have area in it mapped by pages + PT_AF | // accessed flag + PT_KERNEL | // privileged + PT_ISH | // inner shareable + PT_MEM; // normal memory + + // kernel L3 + paging[5*512]=(unsigned long)(MMIO_BASE+0x00201000) | // physical address + PT_PAGE | // map 4k + PT_AF | // accessed flag + PT_NX | // no execute + PT_KERNEL | // privileged + PT_OSH | // outter shareable + PT_DEV; // device memory + + /* okay, now we have to set system registers to enable MMU */ + + // check for 4k granule and at least 36 bits physical address bus */ + asm volatile ("mrs %0, id_aa64mmfr0_el1" : "=r" (r)); + b=r&0xF; + if(r&(0xF<<28)/*4k*/ || b<1/*36 bits*/) { + uart_puts("ERROR: 4k granule or 36 bit address space not supported\n"); + return; + } + + // first, set Memory Attributes array, indexed by PT_MEM, PT_DEV, PT_NC in our example + r= (0xFF << 0) | // AttrIdx=0: normal, IWBWA, OWBWA, NTR + (0x04 << 8) | // AttrIdx=1: device, nGnRE (must be OSH too) + (0x44 <<16); // AttrIdx=2: non cacheable + asm volatile ("msr mair_el1, %0" : : "r" (r)); + + // next, specify mapping characteristics in translate control register + r= (0b00LL << 37) | // TBI=0, no tagging + (b << 32) | // IPS=autodetected + (0b10LL << 30) | // TG1=4k + (0b11LL << 28) | // SH1=3 inner + (0b01LL << 26) | // ORGN1=1 write back + (0b01LL << 24) | // IRGN1=1 write back + (0b0LL << 23) | // EPD1 enable higher half + (25LL << 16) | // T1SZ=25, 3 levels (512G) + (0b00LL << 14) | // TG0=4k + (0b11LL << 12) | // SH0=3 inner + (0b01LL << 10) | // ORGN0=1 write back + (0b01LL << 8) | // IRGN0=1 write back + (0b0LL << 7) | // EPD0 enable lower half + (25LL << 0); // T0SZ=25, 3 levels (512G) + asm volatile ("msr tcr_el1, %0; isb" : : "r" (r)); + + // tell the MMU where our translation tables are. TTBR_ENABLE bit not documented, but required + // lower half, user space + asm volatile ("msr ttbr0_el1, %0" : : "r" ((unsigned long)&_end + TTBR_ENABLE)); + // upper half, kernel space + asm volatile ("msr ttbr1_el1, %0" : : "r" ((unsigned long)&_end + TTBR_ENABLE + PAGESIZE)); + + // finally, toggle some bits in system control register to enable page translation + asm volatile ("dsb ish; isb; mrs %0, sctlr_el1" : "=r" (r)); + r|=0xC00800; // set mandatory reserved bits + r&=~((1<<25) | // clear EE, little endian translation tables + (1<<24) | // clear E0E + (1<<19) | // clear WXN + (1<<12) | // clear I, no instruction cache + (1<<4) | // clear SA0 + (1<<3) | // clear SA + (1<<2) | // clear C, no cache at all + (1<<1)); // clear A, no aligment check + r|= (1<<0); // set M, enable MMU + asm volatile ("msr sctlr_el1, %0; isb" : : "r" (r)); +} diff --git a/10_virtualmemory/mmu.h b/10_virtualmemory/mmu.h new file mode 100644 index 00000000..7c3684e7 --- /dev/null +++ b/10_virtualmemory/mmu.h @@ -0,0 +1,26 @@ +/* + * 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 mmu_init(); diff --git a/10_virtualmemory/start.S b/10_virtualmemory/start.S new file mode 100644 index 00000000..c6495a8b --- /dev/null +++ b/10_virtualmemory/start.S @@ -0,0 +1,81 @@ +/* + * 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. + * + */ + +.section ".text.boot" + +.global _start + +_start: + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // cpu id > 0, stop +1: wfe + b 1b +2: // cpu id == 0 + + // set stack before our code + ldr x1, =_start + + // set up EL1 + mrs x0, CurrentEL + cmp x0, #4 + beq 5f + msr sp_el1, x1 + // enable CNTP for EL1 + mrs x0, cnthctl_el2 + orr x0, x0, #3 + msr cnthctl_el2, x0 + msr cntvoff_el2, xzr + // Setup SCTLR access + mov x0, #(1 << 31) // AArch64 + orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 + msr hcr_el2, x0 + mrs x0, hcr_el2 + mov x2, #0x0800 + movk x2, #0x30d0, lsl #16 + msr sctlr_el1, x1 + // change execution level to EL1 + mov x2, #0x3c4 + msr spsr_el2, x2 + adr x2, 5f + msr elr_el2, x2 + eret + +5: 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 + // for failsafe, halt this core too + b 1b diff --git a/10_virtualmemory/uart.c b/10_virtualmemory/uart.c new file mode 100644 index 00000000..d368d399 --- /dev/null +++ b/10_virtualmemory/uart.c @@ -0,0 +1,126 @@ +/* + * 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|=(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 + + *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/10_virtualmemory/uart.h b/10_virtualmemory/uart.h new file mode 100644 index 00000000..99b2be48 --- /dev/null +++ b/10_virtualmemory/uart.h @@ -0,0 +1,30 @@ +/* + * 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);