commit 7ace64ba9ff98011d37c74bba20890ccbd663ccb Author: bzt Date: Thu Jan 4 18:24:49 2018 +0100 Initial commit diff --git a/00_crosscompiler/OLVASSEL.md b/00_crosscompiler/OLVASSEL.md new file mode 100644 index 00000000..19cccae3 --- /dev/null +++ b/00_crosscompiler/OLVASSEL.md @@ -0,0 +1,112 @@ +AArch64 Kereszt-Fordító +======================= + +Mielőtt nekiugranál az oktatóanyagoknak, szükséged lesz néhány szerszámra. Nevezetesen egy fordítóra, ami +képes AArch64-re fordítani, és a hozzá kapcsolódó programokra. + +Build renszer +------------- + +A fordítás levezénylésére a GNU make-t fogjuk használni. Ezt nem kell kereszt-fordítani, mivel csak az asztali gépen +fogjuk futtatni, nem a céleszközön. Azért választottam ezt az oktatóanyagokhoz, mert a GNU make-re a fordító +lefordításához is szükséged lesz, szóval ígyis-úgyis kelleni fog. + +Források letöltése és kicsomagolása +------------------------------------ + +Legelőször is, töltsd le a binutils és gcc forrásait. Ebben a példában az íráskor legfrissebb verziókat használtam. +Javaslom, hogy nézd meg a szervereket, és a legfrissebbre módosítsd a fájlneveket. + +```sh +wget http://ftpmirror.gnu.org/binutils/binutils-2.29.tar.gz +wget http://ftpmirror.gnu.org/gcc/gcc-7.2.0/gcc-7.2.0.tar.gz +wget http://ftpmirror.gnu.org/mpfr/mpfr-3.1.6.tar.gz +wget http://ftpmirror.gnu.org/gmp/gmp-6.1.2.tar.bz2 +wget http://ftpmirror.gnu.org/mpc/mpc-1.0.3.tar.gz +wget ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 +wget ftp://gcc.gnu.org/pub/gcc/infrastructure/cloog-0.18.1.tar.gz +``` + +Miután végezett a letöltés, csomagold ki a tömörített fájlokat: + +```sh +for i in *.tar.gz; do tar -xzf $i; done +for i in *.tar.bz2; do tar -xjf $i; done +``` + +Szükség lesz még néhány symlink-re mielőtt a fordtást elkezdhetnénk, hozzuk létre ezeket: + +```sh +cd binutils-* +ln -s ../isl-* isl +cd .. +cd gcc-* +ln -s ../mpfr-* mpfr +ln -s ../gmp-* gmp +ln -s ../mpc-* mpc +ln -s ../cloog-* cloog +cd .. +``` + +Források lefordítása +-------------------- + +Oké, két csomagot kell fordítanunk. Az egyik a *binutils*, ami tartalmazza a linker-t, assembler-t és még pár +hasznos parancsot. + +```sh +cd binutils-* +configure --prefix=/usr/local/cross-compiler --target=aarch64-elf \ +--enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit \ +--disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-plugin \ +--disable-linker-build-id --enable-lto --enable-install-libiberty --with-linker-hash-style=gnu --with-gnu-ld\ +--enable-gnu-indirect-function --disable-multilib --disable-werror --enable-checking=release --enable-default-pie \ +--enable-default-ssp --enable-gnu-unique-object +make -j4 +make install +``` + +Az első paraméter megmondja a configure szkriptnek, hogy a `/usr/local/cross-compiler` mappába telepítsen. A második +megadja a célarchítektúrát, amire a most fordítandó eszközök fordítanak majd. A maradék paramétek ki és bekapcsolgat +bizonyos funkciókat, ne foglalkozz velük. Elég annyit tudni, hogy ezek egy beágyazott fordítóhoz vannak optimalizálva. + +A második csomag, természetesen maga a *gcc* fordító. + +```sh +cd gcc-* +configure --prefix=/usr/local/cross-compiler --target=aarch64-elf --enable-languages=c \ +--enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit \ +--disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-plugin \ +--disable-linker-build-id --enable-lto --enable-install-libiberty --with-linker-hash-style=gnu --with-gnu-ld\ +--enable-gnu-indirect-function --disable-multilib --disable-werror --enable-checking=release --enable-default-pie \ +--enable-default-ssp --enable-gnu-unique-object +make -j4 +make install +``` + +Itt ugyanúgy megadjuk a könyvtárat és a célarchitektúrát, mint az előbb. Megadjuk azt is, hogy csak C fordítót kérünk, +mivel a gcc rengeteg nyelvet ismer, amire nem lesz szükség. Ez jelentősen lecsökkenti a fordítási időt. A fennmaradó +kapcsolók ugyan azok, mint a binutils esetében. + +Ha végzett, nézd meg a `bin` mappát a `/usr/local/cross-compiler` könyvtárban. Egy rakás futtatható programot kell +ott találnod. Meggyőződésem, hogy ezt a mappát hozzá akarod adni a PATH-odhoz is. + +```sh +$ ls /usr/local/cross-compiler/bin +aarch64-elf-addr2line aarch64-elf-elfedit aarch64-elf-gcc-ranlib aarch64-elf-ld aarch64-elf-ranlib +aarch64-elf-ar aarch64-elf-gcc aarch64-elf-gcov aarch64-elf-ld.bfd aarch64-elf-readelf +aarch64-elf-as aarch64-elf-gcc-7.2.0 aarch64-elf-gcov-dump aarch64-elf-nm aarch64-elf-size +aarch64-elf-c++filt aarch64-elf-gcc-ar aarch64-elf-gcov-tool aarch64-elf-objcopy aarch64-elf-strings +aarch64-elf-cpp aarch64-elf-gcc-nm aarch64-elf-gprof aarch64-elf-objdump aarch64-elf-strip +``` + +Amik ezek közül számunkra érdekesek: + - aarch64-elf-as - az assembler + - aarch64-elf-gcc - a C fordító + - aarch64-elf-ld - a linker + - aarch64-elf-objcopy - az ELF futtathatók IMG-re való konvertálásához kell + - aarch64-elf-objdump - futtathatók disassemblálásához (debuggolásnál) + - aarch64-elf-readelf - hasznos eszköz a futtathatókban lévő szekciók és szegmensek listázáshoz (debuggolásnál) + +Ha mind az öt fenti futtahatót látod, és hibaüzenet nélkül le is futnak, gratulálok! +Minden eszköz a rendelkezésedre áll, ami ehhez az oktatóanyaghoz kelleni fog. diff --git a/00_crosscompiler/README.md b/00_crosscompiler/README.md new file mode 100644 index 00000000..1b33982e --- /dev/null +++ b/00_crosscompiler/README.md @@ -0,0 +1,112 @@ +AArch64 Cross Compiler +====================== + +Before we could start our tutorials, you'll need some tools. Namely a compiler that compiles for the AArch64 +architecture and it's companion utilities. + +Build system +------------ + +To orchestrate compilation, we'll use GNU make. No need for cross-compiling this, as we are about to use it on the +host computer only, and not on the target machine. The reason I choosed this build system for the tutorials is that +GNU make is also required to compile the compiler, so you'll need it anyway. + +Download and unpack sources +--------------------------- + +First of all, download binutils and gcc sources. In this example I've used the latest versions as of writing. +You are advised to check the mirrors and modify filenames accordly. + +```sh +wget http://ftpmirror.gnu.org/binutils/binutils-2.29.tar.gz +wget http://ftpmirror.gnu.org/gcc/gcc-7.2.0/gcc-7.2.0.tar.gz +wget http://ftpmirror.gnu.org/mpfr/mpfr-3.1.6.tar.gz +wget http://ftpmirror.gnu.org/gmp/gmp-6.1.2.tar.bz2 +wget http://ftpmirror.gnu.org/mpc/mpc-1.0.3.tar.gz +wget ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 +wget ftp://gcc.gnu.org/pub/gcc/infrastructure/cloog-0.18.1.tar.gz +``` + +Once the download finished, unpack the tarballs with these commands: + +```sh +for i in *.tar.gz; do tar -xzf $i; done +for i in *.tar.bz2; do tar -xjf $i; done +``` + +You'll need some symbolic links before you could start the compilation, so let's create them: + +```sh +cd binutils-* +ln -s ../isl-* isl +cd .. +cd gcc-* +ln -s ../mpfr-* mpfr +ln -s ../gmp-* gmp +ln -s ../mpc-* mpc +ln -s ../cloog-* cloog +cd .. +``` + +Compiling the sources +--------------------- + +Okay, now we have to build two packages. One is called *binutils*, which includes linker, assembler and other +usefull commands. + +```sh +cd binutils-* +configure --prefix=/usr/local/cross-compiler --target=aarch64-elf \ +--enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit \ +--disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-plugin \ +--disable-linker-build-id --enable-lto --enable-install-libiberty --with-linker-hash-style=gnu --with-gnu-ld\ +--enable-gnu-indirect-function --disable-multilib --disable-werror --enable-checking=release --enable-default-pie \ +--enable-default-ssp --enable-gnu-unique-object +make -j4 +make install +``` + +The first argument tells the configure script to install the build in `/usr/local/cross-compiler`. The second +specifies the target architecture, for which we want the tools to be compiled. The other arguments turn specific +options on and off, don't bother. It's enough to know they are appropriately tweeked for an embedded system compiler. + +And the second package, of course we'll need the *gcc compiler* itself. + +```sh +cd gcc-* +configure --prefix=/usr/local/cross-compiler --target=aarch64-elf --enable-languages=c \ +--enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit \ +--disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-plugin \ +--disable-linker-build-id --enable-lto --enable-install-libiberty --with-linker-hash-style=gnu --with-gnu-ld\ +--enable-gnu-indirect-function --disable-multilib --disable-werror --enable-checking=release --enable-default-pie \ +--enable-default-ssp --enable-gnu-unique-object +make -j4 +make install +``` + +Here we specify the same directory and architecture as before. We also tell to compile only the C compiler, as gcc +otherwise would support tons of languages we don't need. This reduces the compilation time significantly. The remaining +arguments are the same as with binutils. + +Now check `bin` folder in your `/usr/local/cross-compiler` directory. You should see a lot of executables there. You +probably also want to add this directory to your PATH environment variable. + +```sh +$ ls /usr/local/cross-compiler/bin +aarch64-elf-addr2line aarch64-elf-elfedit aarch64-elf-gcc-ranlib aarch64-elf-ld aarch64-elf-ranlib +aarch64-elf-ar aarch64-elf-gcc aarch64-elf-gcov aarch64-elf-ld.bfd aarch64-elf-readelf +aarch64-elf-as aarch64-elf-gcc-7.2.0 aarch64-elf-gcov-dump aarch64-elf-nm aarch64-elf-size +aarch64-elf-c++filt aarch64-elf-gcc-ar aarch64-elf-gcov-tool aarch64-elf-objcopy aarch64-elf-strings +aarch64-elf-cpp aarch64-elf-gcc-nm aarch64-elf-gprof aarch64-elf-objdump aarch64-elf-strip +``` + +The executables we are interested in: + - aarch64-elf-as - the assembler + - aarch64-elf-gcc - the C compiler + - aarch64-elf-ld - the linker + - aarch64-elf-objcopy - to convert ELF executable into IMG format + - aarch64-elf-objdump - utility to disassemble executables (for debugging) + - aarch64-elf-readelf - an useful utility to dump sections and segments in executables (for debugging) + +If you have all of the above five executables and you can also run them without error messages, congrats! +You have all the tools needed for this tutorial series. diff --git a/01_bareminimum/Makefile b/01_bareminimum/Makefile new file mode 100644 index 00000000..43fca581 --- /dev/null +++ b/01_bareminimum/Makefile @@ -0,0 +1,38 @@ +# +# 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. +# +# + +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 + +kernel8.img: start.o + aarch64-elf-ld -nostdlib -nostartfiles start.o -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/01_bareminimum/OLVASSEL.md b/01_bareminimum/OLVASSEL.md new file mode 100644 index 00000000..6ea8ace0 --- /dev/null +++ b/01_bareminimum/OLVASSEL.md @@ -0,0 +1,35 @@ +Oktatóanyag 01 - A legszükségesebbek +==================================== + +Rendben, nem fogunk semmi érdekeset csinálni, csak kipróbáljuk a környezetet. A keletkezett kernel8.img-nek +be kell tudnia bootolni a Raspberry Pi-n, ahol végtelen ciklusban várakoztatja a CPU magokat. Ezt ellenőrizheted a +következő paranccsal: + +```sh +$ qemu-system-aarch64 -M raspi3 -kernel kernel8.img -d in_asm + ... kimenet törölve az átláthatóság miatt, utolsó sor: ... +0x0000000000080004: 17ffffff b #-0x4 (addr 0x80000) +``` + +Start +----- + +Amikor a vezérlés átadódik a kernel8.img-nek, a környezet még nem alkalmas C kód futtatására. Ezért mindenképp +szükség van egy kis Assembly bevezetőre. Mivel ez az első oktatóanyag nagyon egyszerű, nem is lesz más, nincs +még C kódunk. + +Ne feledkezzünk meg róla, hogy 4 CPU magunk van. Most mind ugyanazt a végtelen ciklust hajtja végre. + + +Makefile +-------- + +A Makefile-unk végtelenü legyszerű. Lefordítjuk a start.S-t, ez az egyetlen forrás fájlunk. Aztán a szerkesztési +fázisban a linker.ld szrkript segítségével linkeljük. Végezetül pedig a keletkező elf futtahatót nyers programfájllá +kovertáljuk. + +Linker szkript +-------------- + +Nem túl meglepő módon ez is egyszerű. Be kell állítanunk a bázis címet, ahová a kernel8.img töltődik, és mindent +ide rakunk, mivel csak egy szekciónk van. diff --git a/01_bareminimum/README.md b/01_bareminimum/README.md new file mode 100644 index 00000000..87eac2bd --- /dev/null +++ b/01_bareminimum/README.md @@ -0,0 +1,32 @@ +Tutorial 01 - Bare Minimum +========================== + +Okay, we're not going to do anything here, just test our toolchain. The resulting kernel8.img should +boot on Raspberry Pi, and stop the CPU cores in an infinite loop. You can check that by running + +```sh +$ qemu-system-aarch64 -M raspi3 -kernel kernel8.img -d in_asm + ... output removed for clearity, last line: ... +0x0000000000080004: 17ffffff b #-0x4 (addr 0x80000) +``` + +Start +----- + +When the control is passed to kernel8.img, the environment is not ready for C. Therefore we must +implement a small preambule in Assembly. As this first tutorial is very simple, that's all we have, no C +for now. + +Note that CPU has 4 cores. All of them are running the same infinite loop for now. + +Makefile +-------- + +Our Makefile is very simple. We compile start.S, as this is our only source. Then in linker phase we +link it using the linker.ld script. Finaly we convert the resulting elf executable into a raw image. + +Linker script +------------- + +Not surpisingly simple too. We just set the base address where our kernel8.img will be loaded, and we +put the only section we have there. diff --git a/01_bareminimum/kernel8.img b/01_bareminimum/kernel8.img new file mode 100755 index 00000000..2276dd4d --- /dev/null +++ b/01_bareminimum/kernel8.img @@ -0,0 +1 @@ +_  \ No newline at end of file diff --git a/01_bareminimum/link.ld b/01_bareminimum/link.ld new file mode 100644 index 00000000..21409159 --- /dev/null +++ b/01_bareminimum/link.ld @@ -0,0 +1,32 @@ +/* + * 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 : { *(.text.boot) } + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} diff --git a/01_bareminimum/start.S b/01_bareminimum/start.S new file mode 100644 index 00000000..5a4647eb --- /dev/null +++ b/01_bareminimum/start.S @@ -0,0 +1,32 @@ +/* + * 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: +1: wfe + b 1b diff --git a/02_multicorec/Makefile b/02_multicorec/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/02_multicorec/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/02_multicorec/OLVASSEL.md b/02_multicorec/OLVASSEL.md new file mode 100644 index 00000000..19ba0113 --- /dev/null +++ b/02_multicorec/OLVASSEL.md @@ -0,0 +1,36 @@ +Oktatóanyag 02 - Többmagos C +============================ + +Próbáljunk valami összetettebbet, mit szóltok? Összetettebb alatt azt értem, hogy most is megállítjuk a CPU magokat, +akárcsak az első oktatóanyagban, de most az egyik magot C-ből! + +Start +----- + +Most már meg kell különböztetnünk a magokat. Ehhez kiolvassuk a *mpidr_el1* rendszer regisztert. Ha nem nulla, akkor +a korábbi végtelen ciklus következik. Ha nulla, akkor meg fogunk hívni egy C eljárást. De ehhez előbb be állítanunk +egy megfelelő vermet, ki kell nulláznunk a bss szegmenst mielőtt kiadhatnánk az ugrás parancsot. Hozzáadtam néhány +Assembly sort, amik mindezt elvégzik. Arra az esetre, ha a C eljárás visszatérne (nem szabadna), ugyanarra a +végtelen ciklusra ugrunk, mint amit a többi CPU mag is épp végrehajt. + +Makefile +-------- + +Egy kisit trükkösebb lett. Hozzáadtam parancsokat a C fordításhoz, de akkor már általánosan. Mostantól ugyanazt +a Makefile-t használhatjuk minden oktatóanyaghoz, függetlenül attól, hány C forrásfájlunk van, és a továbbiakban +nem is szerepeltetem. + +Linker script +------------- + +Hasonlóan, a linker szkript is bonyolultabbá vált, mivel a C-hez adat és bss szekciókra is szükség van. Hozzáadtam +továbbá egy számolást a bss szegmens méretének megállapítására, így egyszerűen hivatkozhatunk rá Assembly-ben, és +nem kell ott molyolni vele. + +Fontos, hogy a text szegmens az Assembly kóddal kezdődjön, mivel ez elé raktuk a vermet, ezért kell a KEEP(). +Íly módon mind a betöltési címünk 0x80000, akárcsak a `_start` cimke címe és a verem teteje. + +Main +---- + +Végezetül, az első C kódunk. Csak egy végtelen ciklus, de akkor is! :-) diff --git a/02_multicorec/README.md b/02_multicorec/README.md new file mode 100644 index 00000000..fe66b93a --- /dev/null +++ b/02_multicorec/README.md @@ -0,0 +1,34 @@ +Tutorial 02 - Multicore C +========================= + +Now let's try something more complex, shall we? By complex I mean stop the CPU cures just like in the first tutorial, +but this time stop one of them from C! + +Start +----- + +Now we have to distinguish the cores. For that, we read the *mpidr_el1* system register. If it's not zero, we'll +do the former infinite loop. If it's zero, then we'll call a C function. But for that, we need a proper stack, and a +zerod out bss segment in memory before the call instruction. I've added some more code to the Assembly to do all of +that. In case the C code returns (shouldn't), we also jump to the same infinite loop the other CPU cores running. + +Makefile +-------- + +It became a bit trickier. I've added commands for compiling C sources, but in a comform way. From now on, we +can use the same Makefile for every tutorial, regardless of the number of C sources, and I won't discuss it any +further. + +Linker script +------------- + +Likewise, the linker script became more complex too, as C needs data and bss sections. I've also added a calculation +for the bss size, so that we can refer to it from the Assembly without any further hassle. + +It is important to start the text segment with the Assembly code, because we set the stack right before it, hence +the KEEP(). This way our load address is 0x80000, the same as `_start` label and stack top. + +Main +---- + +Finaly, our first C code. Just an empty loop, but still! :-) diff --git a/02_multicorec/kernel8.img b/02_multicorec/kernel8.img new file mode 100755 index 00000000..93185e1f Binary files /dev/null and b/02_multicorec/kernel8.img differ diff --git a/02_multicorec/link.ld b/02_multicorec/link.ld new file mode 100644 index 00000000..1352bfb1 --- /dev/null +++ b/02_multicorec/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/02_multicorec/main.c b/02_multicorec/main.c new file mode 100644 index 00000000..e7d114bd --- /dev/null +++ b/02_multicorec/main.c @@ -0,0 +1,29 @@ +/* + * 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 main() +{ + while(1); +} diff --git a/02_multicorec/start.S b/02_multicorec/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/02_multicorec/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/03_uart1/Makefile b/03_uart1/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/03_uart1/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/03_uart1/OLVASSEL.md b/03_uart1/OLVASSEL.md new file mode 100644 index 00000000..04ce36f4 --- /dev/null +++ b/03_uart1/OLVASSEL.md @@ -0,0 +1,33 @@ +Oktatóanyag 03 - UART1, Auxilary mini UART +========================================== + +Ezúttal a hírhedt Helló Világ példát vesszük elő. Előbb az UART1-re írjuk meg, mivel azt egyszerűbb programozni. +NOTE: qemu nem irányítja át alapból az UART1-et a terminálra, csak az UART0-át! + +Gpio.h +------ + +Van egy új fejléc fájlunk. Ebben definiáljuk az MMIO címét, és a GPIO vezérlő szavainak címeit. Ez egy nagyon +népszerű fejléc lesz, majd minden eszközhöz kelleni fog. + +Uart.h, uart.c +-------------- + +Egy nagyon minimális változat. + +`uart_init()` inicializálja az UART csipet, és soros vonalat leképezi a GPIO lábakra. + +`uart_send(c)` kiküld egy karatert a soros vonalra. + +`uart_getc()` fogad egy karatert. A kocsivissza karakter (13) automatikusan újsor karakterré (10) konvertálódik. + +`uart_puts(s)` kiír egy szöveget. Újsor karakternél kiküld egy kocsivissza karatert is (13 + 10). + +Main +---- + +Először is meg kell hívni az uart inicializáló kódját. Aztán kiküldjük, "Helló Világ!". Ha beszereztél USB +soros kábelt, akkor ennek meg kell jelennie a minicom ablakában. Ezután minden, minicom-ban leütött karaktert +visszaküld és kiír. Ha nem kapcsoltad ki a helyi visszhangot (local echo), akkor ez azt jelenti, hogy minden +leütött karaktert duplán fog kiírni a minicom. + diff --git a/03_uart1/README.md b/03_uart1/README.md new file mode 100644 index 00000000..42e07f9c --- /dev/null +++ b/03_uart1/README.md @@ -0,0 +1,32 @@ +Tutorial 03 - UART1, Auxilary mini UART +======================================= + +It is time for the famous Hello World example. We're going to write on the UART1 first, as it's easier to program. +NOTE: qemu does not redirect UART1 to terminal by default, only UART0! + +Gpio.h +------ + +We have a new header file. This defines the base MMIO address, and the GPIO controller's addresses. This file +going to be very popular, as many device needs it. + +Uart.h, uart.c +-------------- + +A very minimal implementation. + +`uart_init()` initializes the device and maps it to the GPIO ports. + +`uart_send(c)` sends a character over the serial line. + +`uart_getc()` receives a character. The carrige return character (13) will be converted into a newline character (10). + +`uart_puts(s)` prints out a string. On newline, a carrige return character will also be sent (13 + 10). + +Main +---- + +First we have to call the uart initialization code. Then we say "Hello World!". If you've purchased an USB +serial cable, you should see it on minicom's screen. After that every character typed in minicom will be +echoed back. If you haven't turned off local echo, that means you'll see every pressed key twice. + diff --git a/03_uart1/gpio.h b/03_uart1/gpio.h new file mode 100644 index 00000000..52fa671d --- /dev/null +++ b/03_uart1/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/03_uart1/kernel8.img b/03_uart1/kernel8.img new file mode 100755 index 00000000..1a126bb4 Binary files /dev/null and b/03_uart1/kernel8.img differ diff --git a/03_uart1/link.ld b/03_uart1/link.ld new file mode 100644 index 00000000..1352bfb1 --- /dev/null +++ b/03_uart1/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/03_uart1/main.c b/03_uart1/main.c new file mode 100644 index 00000000..d2f6850a --- /dev/null +++ b/03_uart1/main.c @@ -0,0 +1,40 @@ +/* + * 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() +{ + // set up serial console + uart_init(); + + // say hello + uart_puts("Hello World!\n"); + + // echo everything back + while(1) { + uart_send(uart_getc()); + } +} diff --git a/03_uart1/start.S b/03_uart1/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/03_uart1/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/03_uart1/uart.c b/03_uart1/uart.c new file mode 100644 index 00000000..0b74e6f4 --- /dev/null +++ b/03_uart1/uart.c @@ -0,0 +1,104 @@ +/* + * 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 carachter 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++); + } +} diff --git a/03_uart1/uart.h b/03_uart1/uart.h new file mode 100644 index 00000000..72f8e315 --- /dev/null +++ b/03_uart1/uart.h @@ -0,0 +1,29 @@ +/* + * 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); diff --git a/04_mailboxes/Makefile b/04_mailboxes/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/04_mailboxes/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/04_mailboxes/OLVASSEL.md b/04_mailboxes/OLVASSEL.md new file mode 100644 index 00000000..83d3a6b2 --- /dev/null +++ b/04_mailboxes/OLVASSEL.md @@ -0,0 +1,34 @@ +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. +NOTE: 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 new file mode 100644 index 00000000..9c3d2cf0 --- /dev/null +++ b/04_mailboxes/README.md @@ -0,0 +1,34 @@ +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 new file mode 100644 index 00000000..52fa671d --- /dev/null +++ b/04_mailboxes/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/04_mailboxes/kernel8.img b/04_mailboxes/kernel8.img new file mode 100755 index 00000000..ec6de0e7 Binary files /dev/null and b/04_mailboxes/kernel8.img differ diff --git a/04_mailboxes/link.ld b/04_mailboxes/link.ld new file mode 100644 index 00000000..1352bfb1 --- /dev/null +++ b/04_mailboxes/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/04_mailboxes/main.c b/04_mailboxes/main.c new file mode 100644 index 00000000..44fdda6e --- /dev/null +++ b/04_mailboxes/main.c @@ -0,0 +1,60 @@ +/* + * 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 command line 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] = 0; // no input arguments + mbox[4] = 0; + 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 new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/04_mailboxes/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/04_mailboxes/mbox.h b/04_mailboxes/mbox.h new file mode 100644 index 00000000..d1f7a352 --- /dev/null +++ b/04_mailboxes/mbox.h @@ -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. + * + */ + +/* 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/start.S b/04_mailboxes/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/04_mailboxes/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/04_mailboxes/uart.c b/04_mailboxes/uart.c new file mode 100644 index 00000000..61b76e24 --- /dev/null +++ b/04_mailboxes/uart.c @@ -0,0 +1,119 @@ +/* + * 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 carachter 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 new file mode 100644 index 00000000..99b2be48 --- /dev/null +++ b/04_mailboxes/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/05_uart0/Makefile b/05_uart0/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/05_uart0/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/05_uart0/OLVASSEL.md b/05_uart0/OLVASSEL.md new file mode 100644 index 00000000..5e633044 --- /dev/null +++ b/05_uart0/OLVASSEL.md @@ -0,0 +1,22 @@ +Oktatóanyag 05 - UART0, PL011 +============================= + +Ebben az okatatóanyagban ugyanazt csináljuk, mint a 4-esben, de most a szériaszámot az UART0-ra küldjük ki. +Emiatt ez a példa könnyen használható qemu-val is: + +```sh +$ qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial stdio +My serial number is: 0000000000000000 +``` + +Uart.h, uart.c +-------------- + +Mielőtt a frekvenciaosztót megadhatnánk, be kell állítanunk egy fix órajelet a PL011 csipben. Ezt levelesládán +keresztül tehetjük meg, ugyanazon a property csatornán keresztül, amit már korábban is használtunk. Ettől eltekintve +ez az interfész teljesen azonos az UART1-ével. + +Main +---- + +Lekérjük az alaplap egyedi szériaszámát, majd kiírjuk a soros konzolra. diff --git a/05_uart0/README.md b/05_uart0/README.md new file mode 100644 index 00000000..1840dd4f --- /dev/null +++ b/05_uart0/README.md @@ -0,0 +1,22 @@ +Tutorial 05 - UART0, PL011 +========================== + +This tutorial does the same as tutorial 04, but it prints the serial number on UART0. As such, it can be used +easily with qemu, like + +```sh +$ qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial stdio +My serial number is: 0000000000000000 +``` + +Uart.h, uart.c +-------------- + +Before we could use a rate divisor value, we must establish a valid clock rate for the PL011. It's done +via mailboxes, with the same property channel we used earlier. Otherwise this interface is identical to the +UART1 one. + +Main +---- + +We query the board's serial number and then we display it on the serial console. diff --git a/05_uart0/gpio.h b/05_uart0/gpio.h new file mode 100644 index 00000000..52fa671d --- /dev/null +++ b/05_uart0/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/05_uart0/kernel8.img b/05_uart0/kernel8.img new file mode 100755 index 00000000..8ed1fa4d Binary files /dev/null and b/05_uart0/kernel8.img differ diff --git a/05_uart0/link.ld b/05_uart0/link.ld new file mode 100644 index 00000000..1352bfb1 --- /dev/null +++ b/05_uart0/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/05_uart0/main.c b/05_uart0/main.c new file mode 100644 index 00000000..44fdda6e --- /dev/null +++ b/05_uart0/main.c @@ -0,0 +1,60 @@ +/* + * 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 command line 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] = 0; // no input arguments + mbox[4] = 0; + 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/05_uart0/mbox.c b/05_uart0/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/05_uart0/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/05_uart0/mbox.h b/05_uart0/mbox.h new file mode 100644 index 00000000..09844dea --- /dev/null +++ b/05_uart0/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/05_uart0/start.S b/05_uart0/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/05_uart0/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/05_uart0/uart.c b/05_uart0/uart.c new file mode 100644 index 00000000..111eb97e --- /dev/null +++ b/05_uart0/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 carachter 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/05_uart0/uart.h b/05_uart0/uart.h new file mode 100644 index 00000000..99b2be48 --- /dev/null +++ b/05_uart0/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/06_random/Makefile b/06_random/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/06_random/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/06_random/OLVASSEL.md b/06_random/OLVASSEL.md new file mode 100644 index 00000000..246e70f4 --- /dev/null +++ b/06_random/OLVASSEL.md @@ -0,0 +1,19 @@ +Oktatóanyag 06 - Hardveres Véletlenszám Generátor +================================================= + +Ez egy egyszerű okatatóanyag lesz. Lekérjük az aktuális értéket (az egyéként nem dokumentált) +hardveres véletlenszám generátorból. Ez arra használható többek között, hogy egy egyszerű, megfelelő +kockadobást szimuláljunk bármilyen játékban. Ez azért fontos, mert hardveres támogatás nélkül csak +kizárólag pszeudo-véletlen állítható elő. + +Rand.h, rand.c +-------------- + +`rand_init()` inicializálja a hardvert. + +`rand(min,max)` visszaad egy min és max közötti véletlen számot. + +Main +---- + +Lekérjük a véletlen számot, és kiírjuk a soros konzolra. diff --git a/06_random/README.md b/06_random/README.md new file mode 100644 index 00000000..fd414301 --- /dev/null +++ b/06_random/README.md @@ -0,0 +1,18 @@ +Tutorial 06 - Hardware Random Number Generator +============================================== + +This going to be an easy tutorial. We query a number from the (undocumented) hardware random +number generator. You can use this to implement a simple, but accurate dice throw in any game. +It is important as without hardware support you can only generate pseudo-random numbers. + +Rand.h, rand.c +-------------- + +`rand_init()` initializes the hardware. + +`rand(min,max)` returns a random number between min and max. + +Main +---- + +We query a random value and then we display it on the serial console. diff --git a/06_random/gpio.h b/06_random/gpio.h new file mode 100644 index 00000000..52fa671d --- /dev/null +++ b/06_random/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/06_random/kernel8.img b/06_random/kernel8.img new file mode 100755 index 00000000..e38c460f Binary files /dev/null and b/06_random/kernel8.img differ diff --git a/06_random/link.ld b/06_random/link.ld new file mode 100644 index 00000000..1352bfb1 --- /dev/null +++ b/06_random/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/06_random/main.c b/06_random/main.c new file mode 100644 index 00000000..3eae8e0f --- /dev/null +++ b/06_random/main.c @@ -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. + * + */ + +#include "uart.h" +#include "rand.h" + +void main() +{ + // set up serial console and random number generator + uart_init(); + rand_init(); + + uart_puts("Here goes a random number: "); + uart_hex(rand(0,4294967295)); + uart_puts("\n"); + + // echo everything back + while(1) { + uart_send(uart_getc()); + } +} diff --git a/06_random/mbox.c b/06_random/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/06_random/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/06_random/mbox.h b/06_random/mbox.h new file mode 100644 index 00000000..ab9e61bf --- /dev/null +++ b/06_random/mbox.h @@ -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. + * + */ + +/* a properly aligned buffer */ +extern volatile unsigned int mbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define MBOX_TAG_SETCLKRATE 0x38002 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); diff --git a/06_random/rand.c b/06_random/rand.c new file mode 100644 index 00000000..4a15a1d3 --- /dev/null +++ b/06_random/rand.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "gpio.h" + +#define RNG_CTRL ((volatile unsigned int*)(MMIO_BASE+0x00104000)) +#define RNG_STATUS ((volatile unsigned int*)(MMIO_BASE+0x00104004)) +#define RNG_DATA ((volatile unsigned int*)(MMIO_BASE+0x00104008)) +#define RNG_INT_MASK ((volatile unsigned int*)(MMIO_BASE+0x00104010)) + +/** + * Initialize the RNG + */ +void rand_init() +{ + *RNG_STATUS=0x40000; + // mask interrupt + *RNG_INT_MASK|=1; + // enable + *RNG_CTRL|=1; + // wait for gaining some entropy + while(!((*RNG_STATUS)>>24)) asm volatile("nop"); +} + +/** + * Return a random number between [min..max] + */ +unsigned int rand(unsigned int min, unsigned int max) +{ + return *RNG_DATA % (max-min) + min; +} diff --git a/06_random/rand.h b/06_random/rand.h new file mode 100644 index 00000000..cd2786b4 --- /dev/null +++ b/06_random/rand.h @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +void rand_init(); +unsigned int rand(unsigned int min, unsigned int max); diff --git a/06_random/start.S b/06_random/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/06_random/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/06_random/uart.c b/06_random/uart.c new file mode 100644 index 00000000..111eb97e --- /dev/null +++ b/06_random/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 carachter to the buffer */ + *UART0_DR=c; +} + +/** + * Receive a character + */ +char uart_getc() { + char r; + /* wait until something is in the buffer */ + do{asm volatile("nop");}while(*UART0_FR&0x10); + /* read it and return */ + r=(char)(*UART0_DR); + /* convert carrige return to newline */ + return r=='\r'?'\n':r; +} + +/** + * Display a string + */ +void uart_puts(char *s) { + while(*s) { + /* convert newline to carrige return + newline */ + if(*s=='\n') + uart_send('\r'); + uart_send(*s++); + } +} + +/** + * Display a binary value in hexadecimal + */ +void uart_hex(unsigned int d) { + unsigned int n; + int c; + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x37:0x30; + uart_send(n); + } +} diff --git a/06_random/uart.h b/06_random/uart.h new file mode 100644 index 00000000..99b2be48 --- /dev/null +++ b/06_random/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/07_delays/Makefile b/07_delays/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/07_delays/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/07_delays/OLVASSEL.md b/07_delays/OLVASSEL.md new file mode 100644 index 00000000..3d23291a --- /dev/null +++ b/07_delays/OLVASSEL.md @@ -0,0 +1,20 @@ +Oktatóanyag 07 - Késleltetések +============================== + +Roppant fontos, hogy a megfelelő időtartamot késleltessünk, amikor alacsony szintű hardverrel bánunk. +Ebben az okatatóanyagban három megközelítést nézünk meg. Az egyik CPU órajel függő (akkor hasznos, ha +a várakozási idő óraciklusban van megadva), a másik kettő mikroszekundum (másodperc milliomod része) alapú. + +Delays.h, delays.c +------------------ + +`wait_cycles(n)` ez nagyon faék, n-szer lefuttatjuk a `nop` (nincs utasítás) utasítást. + +`wait_msec(n)` ez a megvalósítás ARM rendszer regisztereket használ (minden AArch64 CPU-n elérhető). + +`wait_msec_st(n)` ez pedig BCM specifikus, ami a Rendszer Időzítő perifériát használja (nincs emulálva qemu-n). + +Main +---- + +Különböző implementációkkal várakozunk a konzolra írások között. diff --git a/07_delays/README.md b/07_delays/README.md new file mode 100644 index 00000000..30dba2e4 --- /dev/null +++ b/07_delays/README.md @@ -0,0 +1,20 @@ +Tutorial 07 - Delays +==================== + +It is very important to wait precise amounts of time while you're interfacing with low level hardware. +In this tutorial we'll cover there ways. One is CPU frequency dependent (and useful if wait time is given +in CPU clock cycles), the other two are are microsec (millionth of a second) based. + +Delays.h, delays.c +------------------ + +`wait_cycles(n)` this is a very straightforward thing, we execute the 'nop' instruction n times. + +`wait_msec(n)` this implementation uses ARM system registers (available on all AArch64 CPUs). + +`wait_msec_st(n)` is a BCM specific implementation, which uses the System Timer peripheral (not available on qemu). + +Main +---- + +We use different wait implementations between printing strings on serial console. diff --git a/07_delays/delays.c b/07_delays/delays.c new file mode 100644 index 00000000..aba77264 --- /dev/null +++ b/07_delays/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(r>3; diff --git a/07_delays/main.c b/07_delays/main.c new file mode 100644 index 00000000..dd6b421c --- /dev/null +++ b/07_delays/main.c @@ -0,0 +1,54 @@ +/* + * 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 "delays.h" + +void main() +{ + // set up serial console + uart_init(); + + uart_puts("Waiting 1000000 CPU cycles (ARM CPU): "); + wait_cycles(1000000); + uart_puts("OK\n"); + + uart_puts("Waiting 1000000 microsec (ARM CPU): "); + wait_msec(1000000); + uart_puts("OK\n"); + + uart_puts("Waiting 1000000 microsec (BCM System Timer): "); + if(get_system_timer()==0) { + uart_puts("Not available\n"); + } else { + wait_msec_st(1000000); + uart_puts("OK\n"); + } + + // echo everything back + while(1) { + uart_send(uart_getc()); + } +} diff --git a/07_delays/mbox.c b/07_delays/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/07_delays/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/07_delays/mbox.h b/07_delays/mbox.h new file mode 100644 index 00000000..ab9e61bf --- /dev/null +++ b/07_delays/mbox.h @@ -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. + * + */ + +/* a properly aligned buffer */ +extern volatile unsigned int mbox[36]; + +#define MBOX_REQUEST 0 + +/* channels */ +#define MBOX_CH_POWER 0 +#define MBOX_CH_FB 1 +#define MBOX_CH_VUART 2 +#define MBOX_CH_VCHIQ 3 +#define MBOX_CH_LEDS 4 +#define MBOX_CH_BTNS 5 +#define MBOX_CH_TOUCH 6 +#define MBOX_CH_COUNT 7 +#define MBOX_CH_PROP 8 + +/* tags */ +#define MBOX_TAG_SETCLKRATE 0x38002 +#define MBOX_TAG_LAST 0 + +int mbox_call(unsigned char ch); diff --git a/07_delays/start.S b/07_delays/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/07_delays/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/07_delays/uart.c b/07_delays/uart.c new file mode 100644 index 00000000..55fef794 --- /dev/null +++ b/07_delays/uart.c @@ -0,0 +1,127 @@ +/* + * 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 carachter 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/07_delays/uart.h b/07_delays/uart.h new file mode 100644 index 00000000..99b2be48 --- /dev/null +++ b/07_delays/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/08_power/Makefile b/08_power/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/08_power/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/08_power/OLVASSEL.md b/08_power/OLVASSEL.md new file mode 100644 index 00000000..98beb2b1 --- /dev/null +++ b/08_power/OLVASSEL.md @@ -0,0 +1,24 @@ +Oktatóanyag 08 - Energiagazdálkodás +=================================== + +Beépített rendszerek esetén nagyon fontos az energiafogyasztás. A Raspberry Pi 3-on ezért roppant szofisztikált +interfészt találunk. Az egyes eszközöket külön-külön ki be kapcsolgathatjuk. Van egy hátulütő azonban, a GPIO +VCC lábai direktbe vannak kötve az áramforrásra, magyarán nem lehet programból vezérelni őket. Ez azt jelenti, +ha eszközöket kötsz rá, akkor neked kell megoldanod ezen eszközök kikapcsolását (mondjuk egy tranzisztorral, +amit egy másik GPIO adatláb vezérel). + +Power.h, power.c +---------------- + +Az energiagazdálkodás az egyik periféria, amit a qemu egyáltalán nem emulál. Igazi vason szépen megy. + +`power_off()` leállítja az alaplapot egy, majdnem nulla energiafogyasztási szintre. + +`reset()` újraindítja a gépet. Ezt is a PMC kezeli, és mivel nincs a Raspberry-n fizikai reset gomb, roppant +hasznos tud lenni. + +Main +---- + +Megjelenítünk egy egyszerű menüt, majd várunk a felhasználóra. A válaszától függően vagy újraindítjuk a gépet, +vagy kikapcsoljuk. diff --git a/08_power/README.md b/08_power/README.md new file mode 100644 index 00000000..c6c06746 --- /dev/null +++ b/08_power/README.md @@ -0,0 +1,25 @@ +Tutorial 08 - Power management +============================== + +For embedded systems, power consumption is critical. The Raspberry Pi 3 has a very sophisticated +PM interface. You can turn each device on and off idependently. There's a catch though, the GPIO +VCC pins are hardwired, there's no way to turn them off programatically. This means if you connect +some devices to them, you'll have to implement a way to turn those devices off (with a transistor +connected to a data GPIO pin for example). + +Power.h, power.c +---------------- + +The power management controller is one of the periphels that are not emulated properly by qemu. +Works on real hardware though. + +`power_off()` shutdowns the board to a almost zero power consumption state. + +`reset()` reboots the machine. Also handled by the PMC, and since the Raspberry Pi does not have +a hardware reset button, it's very useful. + +Main +---- + +We display a simple menu, and wait for user input. Depending on the input, we reboot the system or +power it off. diff --git a/08_power/delays.c b/08_power/delays.c new file mode 100644 index 00000000..aba77264 --- /dev/null +++ b/08_power/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(r>3; diff --git a/08_power/main.c b/08_power/main.c new file mode 100644 index 00000000..ebce581e --- /dev/null +++ b/08_power/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 "power.h" + +void main() +{ + char c; + + // set up serial console + uart_init(); + + while(1) { + uart_puts(" 1 - power off\n 2 - reset\nChoose one: "); + c=uart_getc(); + uart_send(c); + uart_puts("\n\n"); + if(c=='1') power_off(); + if(c=='2') reset(); + } +} diff --git a/08_power/mbox.c b/08_power/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/08_power/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/08_power/mbox.h b/08_power/mbox.h new file mode 100644 index 00000000..8408d275 --- /dev/null +++ b/08_power/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/08_power/power.c b/08_power/power.c new file mode 100644 index 00000000..38049286 --- /dev/null +++ b/08_power/power.c @@ -0,0 +1,83 @@ +/* + * 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" + +#define PM_RSTC ((volatile unsigned int*)(MMIO_BASE+0x0010001c)) +#define PM_RSTS ((volatile unsigned int*)(MMIO_BASE+0x00100020)) +#define PM_WDOG ((volatile unsigned int*)(MMIO_BASE+0x00100024)) +#define PM_WDOG_MAGIC 0x5a000000 +#define PM_RSTC_FULLRST 0x00000020 + +/** + * Shutdown the board + */ +void power_off() +{ + unsigned long r; + + // power off devices one by one + for(r=0;r<16;r++) { + mbox[0]=8*4; + mbox[1]=MBOX_REQUEST; + mbox[2]=MBOX_TAG_SETPOWER; // set power state + mbox[3]=8; + mbox[4]=8; + mbox[5]=(unsigned int)r; // device id + mbox[6]=0; // bit 0: off, bit 1: no wait + mbox[7]=MBOX_TAG_LAST; + mbox_call(MBOX_CH_PROP); + } + + // power off gpio pins (but not VCC pins) + *GPFSEL0 = 0; *GPFSEL1 = 0; *GPFSEL2 = 0; *GPFSEL3 = 0; *GPFSEL4 = 0; *GPFSEL5 = 0; + *GPPUD = 0; + wait_cycles(150); + *GPPUDCLK0 = 0xffffffff; *GPPUDCLK1 = 0xffffffff; + wait_cycles(150); + *GPPUDCLK0 = 0; *GPPUDCLK1 = 0; // flush GPIO setup + + // power off the SoC (GPU + CPU) + r = *PM_RSTS; r &= ~0xfffffaaa; + r |= 0x555; // partition 63 used to indicate halt + *PM_RSTS = PM_WDOG_MAGIC | r; + *PM_WDOG = PM_WDOG_MAGIC | 10; + *PM_RSTC = PM_WDOG_MAGIC | PM_RSTC_FULLRST; +} + +/** + * Reboot + */ +void reset() +{ + unsigned int r; + // trigger a restart by instructing the GPU to boot from partition 0 + r = *PM_RSTS; r &= ~0xfffffaaa; + *PM_RSTS = PM_WDOG_MAGIC | r; // boot from partition 0 + *PM_WDOG = PM_WDOG_MAGIC | 10; + *PM_RSTC = PM_WDOG_MAGIC | PM_RSTC_FULLRST; +} diff --git a/08_power/power.h b/08_power/power.h new file mode 100644 index 00000000..4216fa55 --- /dev/null +++ b/08_power/power.h @@ -0,0 +1,27 @@ +/* + * 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 power_off(); +void reset(); diff --git a/08_power/start.S b/08_power/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/08_power/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/08_power/uart.c b/08_power/uart.c new file mode 100644 index 00000000..55fef794 --- /dev/null +++ b/08_power/uart.c @@ -0,0 +1,127 @@ +/* + * 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 carachter 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/08_power/uart.h b/08_power/uart.h new file mode 100644 index 00000000..99b2be48 --- /dev/null +++ b/08_power/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/09_framebuffer/Makefile b/09_framebuffer/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/09_framebuffer/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/09_framebuffer/OLVASSEL.md b/09_framebuffer/OLVASSEL.md new file mode 100644 index 00000000..139ca69a --- /dev/null +++ b/09_framebuffer/OLVASSEL.md @@ -0,0 +1,36 @@ +Oktatóanyag 09 - Framebuffer +============================ + +Rendben, végre valami csicsa-picsa :-) Eddig a képernyő sötét volt. Most be fogjuk állítani a felbontását +egy csomó parancsot tartalmazó üzenettel és egyetlen egy mbox_call hívással, majd kirakunk egy képet. Teleraktam +kommenttel az lfb.c forrást (igaz, angol nyelvűek), hogy segítsenek eligazodni a parancsokban. De végeredményben +nem tesz mást, mint feltölt egy int tömböt és meghívja az mbox_call-t, igazán egyszerű. Ha gondolod, megpróbálhatsz +hozzáadni vagy elvenni parancsokat, hogy lásd, mi történik. Használhattam volna az MBOX_CH_FB (FrameBuffer csatornát) +is, de az MBOX_CH_PROP sokkal több mindent tesz lehetővé és sokkal rugalmasabb. + +Fontos tudnivaló a pitch-ről: talán nem tudod, de a video képernyő rasztersorai nem feltétlenül vannak sorfolytonosan +tárolva a memóriában. Például lehetséges, hogy 800 pixelnél (800x4=3200 bájt helyett) 4096 bájton tárolódik minden +sor. Ezért fontos, hogy mindig a dinamikusan lekért pitch értékével számoljuk width*4 helyett a képernyő Y +koordinátáját. + +Arra is érdemes figyelni, hogy a GPU a Raspberry Pi-n nagyon combos. Létrehozhatsz például egy hatalmas virtuális +képernyőt (mondjuk 65536x768), amiből egyszerre csak 1024x768 lesz megjelenítve. Levelesláda üzenetekkel piszok +gyorsan mozgathatod ezt az ablakot, annélkül, hogy pixelbuffereket kéne másolgatni, ezáltal egy nagyon sima +szkrollozó hatást hozva létre. Ebben a példában mind a virtuális, mind a fizikai képméretet 1024x768-ra állítottam. + +Lfb.h, lfb.c +------------ + +`lfb_init()` beállítja a felbontást, színmélységet, színcsatorna sorrendjét. Lekéri továbbá a framebuffer címét. + +`lfb_showpicture()` a framebuffer-be direkt pixelek írásával megjelenít egy képet a képernyő közepén. + +Homer.h +------- + +A kép, Gimp-el C header formátumban lementve. Nincs tömörítve, a pixelek egymás után következnek. + +Main +---- + +Nagyon egyszerű. Beállítjuk a felbontást, és kirajzoljuk a képet, ennyi. diff --git a/09_framebuffer/README.md b/09_framebuffer/README.md new file mode 100644 index 00000000..5d5434c0 --- /dev/null +++ b/09_framebuffer/README.md @@ -0,0 +1,35 @@ +Tutorial 09 - Framebuffer +========================= + +Okay, finaly some eyecandy :-) So far the screen was blank. Now we're about to change the resolution with +several tags in a single mbox_call, then display a pixmap. I've put a lot of comments for each tag and +argument to help you, see lfb.c. But at the end of the day it's nothing more than filling up an int array +and call mbox_call, really simple. If you wish, you can try to remove or add more tags to the message and +see what happens. Could have used MBOX_CH_FB (FrameBuffer channel), but MBOX_CH_PROP gives us more flexibility. + +Important note on pitch: maybe you don't know, but video screens does not necessairly map raster lines +continously in memory. For example it is possible that 800 pixels (800*4=3200 bytes) are stored in 4096 +bytes for every line. Therefore it's important to use the queried pitch value instead of width*4 when +calculating the postition for the Y coordinate. + +Also note that the GPU on the Raspberry Pi is very powerful. You can create a large virtual screen (let's say +65536x768) but display only 1024x768 pixels at once. With mailbox messages you can move that window very fast +without the need of copying pixel buffers, thus creating a smooth scrolling effect. In this tutorial both +virtual screen and physical screen is set to 1024x768. + +Lfb.h, lfb.c +------------ + +`lfb_init()` sets up resolution, depth, and color channel order. Also queries framebuffer's address. + +`lfb_showpicture()` displays a picture in the center of the screen by drawing pixels to the framebuffer. + +Homer.h +------- + +The pixmap, saved with the Gimp as C header file. No compression, pixels are stored one-by-one. + +Main +---- + +Very simple. We set the resolution and display the picture, that's all. diff --git a/09_framebuffer/delays.c b/09_framebuffer/delays.c new file mode 100644 index 00000000..aba77264 --- /dev/null +++ b/09_framebuffer/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(r> 4)); \ +pixel[1] = ((((data[1] - 33) & 0xF) << 4) | ((data[2] - 33) >> 2)); \ +pixel[2] = ((((data[2] - 33) & 0x3) << 6) | ((data[3] - 33))); \ +data += 4; \ +} +static char *homer_data = + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!1)$!Q5*$2=C$\"9B#!U5%BUM'3R((#Z-%S%T#!Y7!A-&!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!#R-?$REJ%2YP%C%W'3F%$BAI$2AM*DJ:#B%7$\"%9%2YR(#^*!A-&" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!#B5A%B]Y$BMK\"1I0'4*+\"B)B!!!!\"1];$\"QV$3>#$C9`$2]T#R9F(D&1" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!#\"1D%S=\\!19,#B)A$B-?(C9N+CMI34Q=?'9>BWY>?75=75E7.T)I'\"E=" + ")4)]!!!\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!1-%%S-X\"QY9#R)>(\"QD=6=FJHUHY\\-L`_1J`_E?`_9A`_AA`_IH`^YIVLM@" + "F9%O5&*#!1I9\"QQ3!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!%3!\\'2=BFXEU:UU?QJ%VW;EI_^-B`^EA`^EA`^IB`^IB`^IA`^IB`^QA" + "`^EB\\^%^K*NK!QQC\"AI2!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!$BUR'BI7P:1ZV+-I6IKV*UOT;%JL9!NU[=K`^QD`^I@`^IB`^IB`^IB`^IB`^IB`^IB`^IB" + "`^MA`^IC`N9<_^^3A(RD%2IG!!!!!!!!!!!!!!!!!!!#!!!!!!-*!!!%!!!!!!9," + "!!!$!!!'!!%\"!!5/$\"-=!!!%!!!!!!!!!!!&#\"!9!!5.!!!!!!!!!!%\"!!!$!!!$" + "!!%'!!!!!!!$!!!!!!=1#A]:!!!&!!!!!!!\"!!50#!Y8!!)*!!!!!!!$!!!+!!-*" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "#RANE7QKS*=NUJQOT;!LT:UM\\M1F`^M@`^I@`^IB`^IB`^IB`^IB`^IB`^IB`^IB" + "`^IB`^IB`^ED`NIH[>2V.%*/!!!!!!!!!!!!\"1A+=Y'.O<`$8WJ^DZGCP-,)3&NN" + "G;7MK\\;])$64I\\#ZQ]H-J\\#U(CU_$C-PH[KRR-P1LLH\"(DB0!!!!(#Y^I+WXL,;^" + ";(\"]OM$'=([/(D\"&KLD!QML/I[SR'3M['#M]JL+`R-H*K<3\\&SV&=Y?:PM@-78+(" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!QU:" + ".CU?WKAUT;%JU*YOTK!MTJQK_N-G`^E>`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^IB" + "`^IB`^IB`NMA_^I?`_^)/9" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1%\"!R)G" + "FX5OV;)NTJYMTJ]LTJ]LT[%I_N5E`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^IB" + "`^IB`^IB`^M@`^AC`.US`_W6%\"QO!!!!!!!!!Q5(?I3/`@\\_LL#Q[?@H````F*/4" + "````J[?HY?,B\\/XOH;#@```_R=D,P=$\"````J+;I\\O\\P[/PO!!U;'3)OX/,H_`PZ" + "HJ[?````F:C=X?$C]P,SH*[@_PL[S=L,Q-$%````G:K<\\O`OZ/DL>H[%````9XC1" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-((31P" + "R*=QU*YJTJ]LTJ]LTJ]LU+)K_N5E`^EA`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^IB" + "`^IB`^IB`^IB`^EC`>AB``/\"8&R1!AQ=!!!!!1)$9W^[_@L]S]X/^P^,T-+6$BAK!1)%!!!!0UJ6]@0V````Z/0DYO,B````" + "````6'W$ZO@G\\?XNHJ_B`P``RML,Q-0&````J+?I\\O\\PZOHM!!U<'#)NX?,G_PT[" + "E*#1````F*C\\_`O[?TM77S!^`4S+TV4" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!AA.4%=Y" + "TZUMT+!NTJ]LTJ]LTZ]LT*QI_.%H`NM?`NE@`^MA`_9@`_=B`_%9`NE?`^EC`^E>" + "`^AB`NAA`^Q:`_-=`_1B`^YA^.RCDIRO&2YJ!!!!,TF$Z?DH`P``R=<'R=8(````" + "`0PX7XS>PM@,_0HYT-\\/````N,X$M!!51'CEXX/0E_@P[" + "EZ+6````G*[HR]X0_PL[T=T/````NLX!L\\?`````S]T._@HVV.L>8X'+\\_\\J1V6N" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-*1U9^" + "TJMKTZ]MTZ]LTJ]LTJ]KSZQJ[M)J`^I@_.ABW-%OE(IMAG]JO+%W^N5N_>A@`.I;" + "`.AC_>=CZ=9VIY]QG9-OS,)T_>ARS<6L+$2#!!!!(CEUU^D;^`DYJL3]GKCW_@LY" + "Y/4I0%60.6:N]@,V_@L[\\@$S2VJH0&\"=\\?`S_PPY_PX]4G;\"!!!!(#Z\"W>`@]P4T" + "DZ+4`0X^F+/T3GO%^P8V_PP[]0(R37\"W1&>K[OXQ_@LW_@H[06NZ>YG6```_5GC&" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-(*#QO" + "S:ERTJ]KTJ]LTJ]LTJ]LT:QMY<=GPKAHD96EDYW;Q]84T.(&CAX!!%'!!!&&CE[0%F:(#V!!!)'!!!!\"1I0%2]N%\"]P" + "%\"QH%\"]P$2MH!!!$'CI\\15Z<&SI_!!!\"!!)'&S5W0%F8(#U_!A5+$\"EE&CA^#B5B" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)$#2-A" + "P:-YTK!ITJ]LTJ]LTJ]KWK=T?6I1%1^,C]C$\"%6!!)(!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\"\"!?" + "4$QCX+ERT:]MTJYNTJYJ=&UX]P,T``T_]P,T[OLK`````P\\_`P\\_`P\\^`@X\\````" + ">H:Y[?HK```_`P\\_`P\\_````\\?TNXN\\AV^45%#B#!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1)'&S-O4V&*8&F(" + "0%&\"#QY4!!%'!!-)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!)$!!E@,#5D,#UN-#]MOJ)VRZIIXM)EI:%J%BQL!!!#!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + ")C=QSJENU;!LUK%MRZ=KCY\"K_PL\\`@X^@8N^(2U>`````````P\\_`P\\_`P\\_````" + "L[_QR]@)```_`@X^`@X^````KKCK35J,_P8P#\"Q\\!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)$&C1QDH!WRJ9ISJIH" + "TK5P/$-J-4%O*#EN\"2-F!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!1-&%BQOFXYR]MEB^^EHD(9FAW!FY<%N_NAD`>I>C(QQ$29E!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "%#!TGX9FV+5TOI]JRZAOF)NY`@T^```_RM0'H*S=`````P\\_`P\\_`P\\_`P\\_````" + "L+SMR]@)`````@X^_`P\\`@X^^P4W^`8ZR=$!$SJ%!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\"AU2;6=YTK%OVK%I^>)G" + "DX=IE()NT:QMTZIO:65Q$REL!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!\"QU9=6MP]=1H`?!>`^A@``!G@W9EJH]MW\\5IY--?RKIH+T9^!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)$\"B%?" + "!AY>>6UKL)-M.3AAG8=GC8B7^@8W`0X^`````````@X^`P\\_`P\\_`P\\_`P\\^````" + ":72HM\\#UM<#KHZO1CY.SE)J`Q]8&````5FJI&3-R!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!QM3)3QX;&!A?W!KJI]DMJIL" + "A'!DW[=UZLUD^^-B_N-K5F%R!AA.!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!1E4!!UJ+SQM=F1DWK9O]N!A`^ME`NI7[=MX/#9:?W)EEXM>F(QH/DAM!!UB" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!A5*&3>\"" + "#S\"\"7V!Y>6ECL)5X;6!A@V]FT=L.`````@X_`P\\_`P\\_`P\\_`P\\``P\\`````KK?T" + "9VUXQL\"@TLB4X=B6]>FAZ^S';'&8AI;0(3E\\!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!AQ8/4=PLYAOV;]FX])FS;]B9V5A" + "FX-K[,QI`NM?`_1FK:-A9F)H%BQM!A]?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!%%)35HQKEQ]MY@MZQI6U!BW+EO^^1D`^]O3DM9N:5K_>1D`^ED`^AB_^9S7V5Z" + "\"1QB!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!A5)#BUT" + "$#![04=U;6)FTZMR`^YWFY^E)#=Q#!Y3!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!$RAEJ9!RV[5G`.AA`^EF`^I=_.5I" + ">'%HWLIJ_^AH8%Q9D7UORZ9PN)QX.T5Q!15-!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "$\");D8YI`^U=`^I@`_1DT\\9J75A:S+)Q9EU=Q:QR`^Y@`^IA`NI?`^M>`NI8Y-R4" + "\"1U=!!%$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1-'$2YX" + "$\"AJ%R5:85MHUZYNF8-EI8=LRZIS;FIUO=?`>AB`^AA`NIC`^AD[=-D:6MSI*2>%\"5;!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11(,T!OR:=PYLUD^.%G`NI>`^EA`^Q@" + "X]-I@'YI?GAEK)%VY;]J[<]C_^-?W,MJ*#QL!!%$!!!!!!!!!!!!!!!!!!!!!!!!" + "'C%LMY]E`^MJ`.Q:`>EC`^YAV\\EM44I>FH)K_^9F`^M@`NE<`.MP]>-[_^=<\\^%[" + "/$U`!!%%!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%#$\"MS" + "!A1(#B5E?7!FV*YNS*IOQJ-MT[!JX,-CR+QGIZ-_I9^3K*F0OK:&W`NE;" + "`_E^?WV.CGAIX,!F^N)D`^QA_.AEY]9F;'5Y!!)'!!!!!!!!!!!!!!!!!!!!!!!!" + "*C]XGGUJI9EP`^]D`^AB`>M=^N=>?W=GP:9E`^M?`N=<_^=LZNO\"B8!L_^A=]^5Y" + "3EJ#!!!\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1%\"$\"Q[" + "!1-)#B%?EX%RV*]OT;!JTJ]LT:ULYL9J`^IC`^U;__%HP+-P8UQ41#]40SY@/SI>" + "/3E7-C1/.31:7U=TDX.;S;2]SL32?8\"G'#V&$R9>!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-'5UIYU:QK_.=>RKAIB8-W`_:$`.9O" + "``6\\=WR,M9AH_MYI`NI>_NYH;FQAWLYKA(J(!!%'!!!!!!!!!!!!!!!!!!!!!!!!" + "(#-GIHYI*BA3J)MN^N)A`^EE`>I=FHYCJIQE^.=Z]NN=VM:\\:&9SX]=A`NE=^.J)" + "55V$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "\"QY:.DIN8UY@E8)LSZUOT[!LTJYKZA>_N^B" + "8V^7!Q=/!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!QU?" + "<7)MX\\]HZMIKT,!AS*MNTJ]KT:YKWKUN@GEH?&Z+M)ZHT;F[U+R\\U+Z_U;^_U+Z_" + "U+Z_U+^^UL\"_U\\'!U\\'!U\\\"_UL#\"U;^`WL7$R+O&2%.':':EC9*Y-DR+!A5)!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!-.(31OH(QNTJQK_-]D`^Q@\\^!E8&-=P+)G" + "T\\)BU,5J?71GL:5>MJEH>'-IN*MC]NJ3,TF#!A1'!!!!!!!!!!!!!!!!!!!!!!!!" + "!15)6EQMRJIQ955E9%I=@'!I2D)8CWYJ]=MI]=UMOK!>KJ)F`^]?`^I@`>M>_NR)" + "QLC#(3UY!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%#$2-D" + "P*-NV^%QJFMV,\"`UL##UL#!UL#!UL&_UL#!" + "UL#!UL#\"UL#\"UL#!UL#!UL#!UL#!UL#\"V,'!SKZ[P;6`V" + "`^AA`^ICZ]ADL:9SM:IJXI;" + "`_>GFZ\"K(T&)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%##R-?" + "QJAZD'AGH(1RDX%HW;1PU+!JNY]P3TALNZ&IU\\&_U,'\"UL\"`UL\"`UL\"`UL&^UL\"_" + "UL#!UL##UL##UL\"`UL'!UL#!UL#!U\\#\"U<'\"UL&YPJZTS[:[SL#\"4V\"3!Q=-!!!!" + "!!!!!!!!!!!!!!!!!!!!!AA0+4%VKI%LVK)NSZYKW[]I`NEA`NICKJ!LZ=9A`^MC" + "`NIA`.MC`^MC`_!<`^Y@`_1`T,^])S]_!!%%!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!9.(S1MMIAKW;EPU[-LU+!KT:QLY\\5J`^M@U\\9FZ]9F`^IA`^IB`NIC`NM?" + "`.IB`_BCHJ:R$BML!A-$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1Q:" + "6UINR*5QWK9XU;-WP*!IW+AN:UIEBGB2S[6XU<*^U<&`UL&`UL&_UL&_UL&_UL&_" + "UL\"`UL#!UL'!UL&_UL&_UL#!UL#!UL#\"UL3!O*>K3DQPPJNPIZ'\"$2AJ!!!!!!!!" + "!!!!!!!!!!!!!!!!!!97,D)RKY%MV+%OTZYMV;1K^M]B`^MB`^EA_>9C`>A>`^ID" + "`^IB`^IB`^A>_>II`_NHR\\FZ.U.-!A=0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!19,+3YVMYALU+!MTJ]LTJUMW;IM`^Q<`^M@_^I@`^IB`^IB`^IB`^IC" + "`NIC_NA?`>Z2H*>Q%3!S!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "\"B!<,41W4$A72D-=#!5&R;7(&#-Q$2AE!A5*!!!!" + "!!!!!!!!!!!!!!=71$=OQ*5SUK!LSK%MU:YI^-QF`^IB`^IB`^ED`^I@`NMC`^EA" + "`^IB`^EA_^EM`_[*JJBS*$.\"\"1E0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!A=.-$)PN)]NUZ]MTZ]NT:MH^]YI`^M?`^IA`^IB`^IB`^IB`^IB" + "`^IA`^M?`>AA`O.5EYRC)$\"%!!-'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!\"1M>&UKX;EKPJ)M54QKQ*:MT;R]UL&_UL&_UL'!UL#!UL#!UL#!UL#!" + "UL'!UL'!UL##UL#!UL#!UL#!UL#!UL#!V<3\"R+\"VNJ*ML*:U\"2%G!!!!!!!!!!!!" + "!!!!!!!!\"Q];4UI[QZEQUZ]LT:YMUK9H^-YD`^M@`^IB`^IB`^IB`^IB`^IB`^MA" + "`^ID_^M?`O:YA8BF!2-J!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!E90DAKVK-QU:]LU*UQV[AE`>=D`^IB`^IB`^IB`^IB`^IB" + "`^IB`^IB`^E?`>E@`_20M[FV*D%^!QE2!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!1U=75ADX;IMOIYK75-TQ*BKU+Z\\UL&_UL&_UL&_UL&_UL&_UL#!UL#!" + "UL'!UL'!UL##UL#!UL#!UL#!U\\#\"KYZHK)VMXLO+[];56V2-$2QO!!!!!!!!!!!!" + "!!!%\"!YA;6=QS*ANUK!KTJQRV[MF^N%C`^QB`^IB`^IB`^EA`^IB`^IB`^IB`^IB" + "`>A=`_*>K;\"U&#-U!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!\"B-K651AW[ATT+%LU*]IZ\\QH`^IA`^ID`^IA`^IA`^IB" + "`^IA`^IB`^EB`^IB`^A?`^V!S\\^[+$6\"\"1M4!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!922DIAXKQOTK!Q0SUCQZNLT[V]UL#!UL\"`UL&`UL&^UL&_UL#!UL#!" + "UL#!UL#!UL'\"U<'!U<'!U<'\"U,*_U,##2$5P1%B11UF7(#Z$!!!!!!!!!!!!!!)&" + "&#%QDH!QUK%QTZ]KTJQPW+MF_^5E`^IB`^IB`^IB`^IB`^IB`^IB`^MA`NEE`NE;" + "_^Z%Z.33)T%_\"1Q0!1-&!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!%2YMCGIPT[%NTJYNU;)I]]EE`^IA`^I?`^IB`^IB" + "`^IB`^IB`^IB`^IB`^IB`NA<`_%[X=NS36.9#2-A!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!9/.3A7X[USV[=R7$]?GXRAU;N]UL#\"UL#!UL&`UL&_UL&_UL#!UL#!" + "UL#!UL#!UL'!U<'!U<'!U,'\"W,'#HY:E)T\"#!!!!!!!!!!!!!!!!!!!!!!9.)SUU" + "GX1HU[-ITJYLT:UMXA>`^]Q[N6C=(\"C#REM!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!AA2,C5;X[UWUK%KM)ET5T]RRK*VUL&`UL##UL&`UL&`UL&`UL\"`UL\"`" + "UL\"`UL\"`U\\&`UL'!U<'!XLS)KI^G,$-`!!)&!!!!!!!!!!!!!!!!\"21H4E9TN)IN" + "V[1PTZ]LT*UNYL=D`.9C`^EA`^EB`^IB`^IB`^IB`^IB`^IC`^I@`^E@`>IE_O:[" + "<'N9\"B%B!A1%!!!!!1)$!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!50/3]CU;=WU*YNTZ]MU;-H]]UF`^I@`^IA" + "`^IC`^IB`^IB`^IB`^EA`^IB`^IB`^I@`>MA_/\"8F:\"H%35^#B%;!!!!!!!!!!!!" + "!!!!!!!!!AE2,C=;Y+UXTZ]NUK%OA'%MA'6-U\\/!UL&\\UL&`UL#!UL#!UL&_UL&_" + "UL&_UL&_U\\&_U,+\"YEC`^IB`^IB`^IB`^IB`^IB`^IB`^IA`NMC`^AE_^=B`/:GFJ\"Q" + "&SE\\!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!E<651BT[-LT[!LTJYOV+=J^]]G`^I?" + "`^IC`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^EA`>A<`_6-P+VH*T%Z\"!I3!!!!!!%$" + "!!!!!!!!!!9//#M;X[QTT;!LTK!LTJ]M9UAABX\"7SKS!V,+#V,+\"U\\'!U\\&`U\\*`" + "V,*`V,.`U\\&`P*ZW9VB+%S1X!!!!!!!!!A9/%#%T\"R-C'S-MGH)GW+9RT;!KU*YM" + "U;!I\\-)F`^I?`^I@`^IB`^IB`^IB`^IB`^IB`^IB`^IB`>ED`>A=`_22R\\O('35Z" + "!!%#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!#!Y<=&UOU:]NTZ]JT*]MVK=I^]]D" + "`^QA`^IA`^IB`^IB`^IB`^IB`^IB`^IB`^IB`^IB`.E@`^]OVL^+6F5V#AU=)39T" + "!!M9!!!!!!E64$QCWKIOT:]JU;%LV+)NW;MOJI]B=&YWDH6:N*6TSKF]U\\#&S[NY" + "O*BXG9\"E?7B+9&F'#B5E!!!!!!!!!!1//U\".J+'E=(\"U6%IYH8AJU+%NTJULT[)M" + "\\=-E`^EB`^EB`^IC`^IB`^IB`^IB`^IB`^MB`^IA`^IB`N=>`_&-U-#!,$R+\"!Y7" + "!!%\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%#$R5@H(ASU[!NTJ]OTJ]LV;9G" + "^^!C`^IA`^EB`^ID`^IB`^IB`^IB`^IB`^IB`^IB`NMA`^IB`^EC_>=BH9QI3%\"!" + ";WFN\"\"!I!1Y>;F1EZ\\1[V;9ZR:AQLY9KK))ER;IBP[5AC(5D7)]9%YU6UMQ" + "='1SI)I@XM:3T<[-!QA/!!!!!A1'-4Z0Q],#Y.@;Y^L8V=L(B9*`<6-KTK%L]MQE" + "`^IB`^IC`^IB`^IB`^IB`^IB`^IB`^IB`^MC`>MB`N=?`>MZZ^7,/52)\"QY7!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!))&\"9@LI9VV;)JU*]MTZUP" + "V[EF_>%E`^I=`^EB`^IB`^IB`^IB`^IB`^IB`^IB`^ID`^IA`^MB`NAB^>A>G:CAFZ/2@8W\"<7.(S,!M_NAE" + "`^U>`^Y?`?&0R\\K((SZ*.5JE.%.8A8R\\WN<4Y^82X>@7XND9Z.H:JKCL@W]^\\-QF" + "`^Q>`^IA`^IB`^IB`^IB`^IB`^IB`^IB`^IB`>E>_NQT]_/,87&8#2-B!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1.(#%EKI-OU;)LTJ]N" + "T:UMW;II_>%D`^M@`^IA`^ID`^IB`^IB`^IB`^IB`^IB`^IB`^IC`^MXY.T`>M[TM#,E9W.Q,KUWND7D)O/R,[]Y.<6Y.<5X.44Z?(C````V.4=?8*8" + "U,1=`^Q?`^M@`^IC`^IB`^IB`^IB`^IB`^EB`.QS`OG,=8\"@#B-H!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1-',CYFPZ%TTZ]L" + "TK!LTZQOV[=G_>%G`^I@`^IC`^IB`^IB`^IB`^IB`^IB`^IB`^EB`_)BCHEAQ]8+" + "`````0T\\Z?(A7665M[SLZ>P;XN85^`4R`P`_`P\\_`P\\_````GZK=K+?J^@D[559\\" + "Z]ML`^Q>`.AKV=;-F)_/;'2H````PLW_J+'>X^L8W^<5\\?LK`PX``P\\_`P\\_\\_`P" + "@H28Y--H`.MA`^MB`^IB`^IB`^IB`^EA`.AC`?K&>X:@%C!S!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1./D1HRZAO" + "U;!JTJ]LT:]LV[MI_>5A`^MC`^IB`^IB`^IB`^IB`^IB`^IB`^QC]>!A<72-_0DZ" + "`P\\_`@X^_`LYT]T*96R;V-\\,YN\\<`````P\\_`P\\_`P\\_````/DA\\````````\\/TQ" + "5%AA^>5A`>AEWMS&3%6&V^@9````^P\\E=7J+]N1B`^MA`^IB`^IB`NE?_^AD__:\\H:6S%3-[!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!95149F" + "QJ1OU+%LTJ]LT:YMW+UH_N1B`^MA`^IB`^IB`^IB`^IB`^EB`_!AIYQAL;WR````" + "`P\\_`P\\_````_@@VGZC7G:75^@,S`````P\\_`P\\_````XNX?='ZR`````@X^````" + "QM(\"H)=I_NA;W=G$6VB6R]@(````````5V25ZO4E`````P\\_`P\\_`P\\_`P\\_`P\\_" + "````V>0=EG`_VYK;*Y'CQ[!1)#!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!AE3" + "24IKSJIOTK%IT:]PT:YKW+MG_^5C`^M@`^IA`^IA`^EC`>M>\\-UGW]`,S``\\```X```X`````J+/EQM($`````P\\_`P\\_" + "_PP\\E)K!X=N#>'F(Z/8J8FV?\\OXO````N\\7WDI[1`````P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_````S]X&FI-B`NQC`.E:`_FQJ*VV%S%R\"R%5!!%#!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!1I84$UJSJMTU;!JTJ]LT:UMW[QH_^5F`^IB`^IB`^I@`^IED(MKX.T=`````P`^" + "`P\\_`P\\_`P\\_`P\\__`PYC);&SMH*XN\\?W^PB)3'[OLK`P\\^`P\\_`P\\_" + "```_^PYM->>'N?_0@[`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_``\\`````:W:I^`@X`````P\\``P\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_\\/TNEZ+8\\/TM_`P\\`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P``<7RE*$B-\"QY4!!!\"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!=4.3]GPJ1PU+!MTJ]LTZUKT[IK;F]]Y_DH```^`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_``\\`````O,;YO,GY`````P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`0T]GZK?XNTA``\\```\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_````BY3($2QK!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!92-CEEKI-PV;5PRZ=O:F)XS=H/`````@\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_`P\\_````[OHKQ=(\"`````P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_````O\\K]K;?K`````P\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\``P\\]```]86\\/DH`PX^`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_````='ZQT-P-`````P\\_`P\\_`P\\_`P\\_`P\\_" + "````^P8VG:O?&39^!Q5)!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!Q9)$\"9EIJW?[_$?X^H6Y.@6X><4Z_4B_`PZ`````P\\`" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_````Z/0E76>;`````P\\_`P\\_```_``````\\\\" + "S-L*8':U#\"1H!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!$%\"IL?XK\"XN@2YNP:Y.<5X><5Y>P:^@8T`P``" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_````3%6*```````````````_P\\[_=(K)" + "'35V!A9+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1/.4>#KK3EV>(0YNH7XND5X>H8\\/HG" + "`0T\\`P```P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_````\\/TMA9#$Q,`\"V>8:CIO30UJ9%3!R!!-*" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!%&!!A4-DB%=H.]J:_CT-<%UMX-" + "W^87[/XO$&#-X\"A9'!1-&!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!%\"!A1'!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!QQ>@8W$\\/8C" + "Z_(>^P0Q`````P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_```_````D:'5%CE\\!Q5&\"!M2!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!%\"!A5)!!!!!!!!!!%#!A1'!!%#!!!!!!!!!!!!!!9/15>6Y><5Y.85" + "Z.X=`@X]`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`@`_````LK[W'SE`#\"!;!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!%\"\"AQ4!!!!!!!!!!!!!A9+)T2.RLW_Y>D:W^85" + "^`4T`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_" + "`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`P\\_`@X^`@X\\G*_H&SI`!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + ""; diff --git a/09_framebuffer/kernel8.img b/09_framebuffer/kernel8.img new file mode 100755 index 00000000..4fb7f868 Binary files /dev/null and b/09_framebuffer/kernel8.img differ diff --git a/09_framebuffer/lfb.c b/09_framebuffer/lfb.c new file mode 100644 index 00000000..a3857d40 --- /dev/null +++ b/09_framebuffer/lfb.c @@ -0,0 +1,111 @@ +/* + * 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" +#include "homer.h" + +unsigned int width, height, pitch; +unsigned char *lfb; + +/** + * Set screen resolution to 1024x768 + */ +void lfb_init() +{ + mbox[0] = 35*4; + mbox[1] = MBOX_REQUEST; + + mbox[2] = 0x48003; //set phy wh + mbox[3] = 8; + mbox[4] = 8; + mbox[5] = 1024; //FrameBufferInfo.width + mbox[6] = 768; //FrameBufferInfo.height + + mbox[7] = 0x48004; //set virt wh + mbox[8] = 8; + mbox[9] = 8; + mbox[10] = 1024; //FrameBufferInfo.virtual_width + mbox[11] = 768; //FrameBufferInfo.virtual_height + + mbox[12] = 0x48009; //set virt offset + mbox[13] = 8; + mbox[14] = 8; + mbox[15] = 0; //FrameBufferInfo.x_offset + mbox[16] = 0; //FrameBufferInfo.y.offset + + mbox[17] = 0x48005; //set depth + mbox[18] = 4; + mbox[19] = 4; + mbox[20] = 32; //FrameBufferInfo.depth + + mbox[21] = 0x48006; //set pixel order + mbox[22] = 4; + mbox[23] = 4; + mbox[24] = 1; //RGB, not BGR preferably + + mbox[25] = 0x40001; //get framebuffer, gets alignment on request + mbox[26] = 8; + mbox[27] = 8; + mbox[28] = 4096; //FrameBufferInfo.pointer + mbox[29] = 0; //FrameBufferInfo.size + + mbox[30] = 0x40008; //get pitch + mbox[31] = 4; + mbox[32] = 4; + mbox[33] = 0; //FrameBufferInfo.pitch + + mbox[34] = MBOX_TAG_LAST; + + if(mbox_call(MBOX_CH_PROP) && mbox[20]==32 && mbox[28]!=0) { + mbox[28]&=0x3FFFFFFF; + width=mbox[5]; + height=mbox[6]; + pitch=mbox[33]; + lfb=(void*)((unsigned long)mbox[28]); + } else { + uart_puts("Unable to set screen resolution to 1024x768x32\n"); + } +} + +/** + * Show a picture + */ +void lfb_showpicture() +{ + int x,y; + unsigned char *ptr=lfb; + char *data=homer_data, pixel[4]; + + ptr += (height-homer_height)/2*pitch + (width-homer_width)*2; + for(y=0;y>3; diff --git a/09_framebuffer/main.c b/09_framebuffer/main.c new file mode 100644 index 00000000..108c03d5 --- /dev/null +++ b/09_framebuffer/main.c @@ -0,0 +1,42 @@ +/* + * 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 "lfb.h" + +void main() +{ + // set up serial console and linear frame buffer + uart_init(); + lfb_init(); + + // display a pixmap + lfb_showpicture(); + + // echo everything back + while(1) { + uart_send(uart_getc()); + } +} diff --git a/09_framebuffer/mbox.c b/09_framebuffer/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/09_framebuffer/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/09_framebuffer/mbox.h b/09_framebuffer/mbox.h new file mode 100644 index 00000000..8408d275 --- /dev/null +++ b/09_framebuffer/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/09_framebuffer/start.S b/09_framebuffer/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/09_framebuffer/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/09_framebuffer/uart.c b/09_framebuffer/uart.c new file mode 100644 index 00000000..55fef794 --- /dev/null +++ b/09_framebuffer/uart.c @@ -0,0 +1,127 @@ +/* + * 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 carachter 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/09_framebuffer/uart.h b/09_framebuffer/uart.h new file mode 100644 index 00000000..99b2be48 --- /dev/null +++ b/09_framebuffer/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/0A_pcscreenfont/Makefile b/0A_pcscreenfont/Makefile new file mode 100644 index 00000000..a91c36ed --- /dev/null +++ b/0A_pcscreenfont/Makefile @@ -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. +# +# + +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 $@ + +font.o: font.psf + aarch64-elf-ld -r -b binary -o font.o font.psf + +kernel8.img: start.o font.o $(OBJS) + aarch64-elf-ld -nostdlib -nostartfiles start.o font.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/0A_pcscreenfont/OLVASSEL.md b/0A_pcscreenfont/OLVASSEL.md new file mode 100644 index 00000000..606fe6c3 --- /dev/null +++ b/0A_pcscreenfont/OLVASSEL.md @@ -0,0 +1,32 @@ +Oktatóanyag 0A - PC Screen Font +=============================== + +Képeket kirakni poénos, de mindenképpen szükség van többre, karakterek megjelenítésére is. Alapvetően +a fontok nem mások, mint képek minden karakterhez (glyphek). Ehhez az oktatóanyaghoz azt a PC Screen Font +formátumot választottam, amit a Linux Console csomag is használ. + +Lfb.h, lfb.c +------------ + +`lfb_init()` beállítja a felbontást, mélységet, színcsatornákat és visszaadja a framebuffer címét. + +`lfb_print(x,y,s)` megjelenít egy szöveget a képernyőn. + +Font.psf +-------- + +A font fájl. Bármelyik használható a /usr/share/kbd/consolefonts mappából. Unicode táblákat nem támogatja. +A karakterek glypehnek való megfeleltetése ezen táblázat által (a meglévő egy-az-egyhez megfeleltetés helyett) +házi feladat, Rád van bízva. Ezt a fontot az eredeti IBM PC VGA ROM-jában található 8x16 fontkészletből generáltam, +és 127 glyphet tartalmaz. + +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. + +Main +---- + +Nagyon egyszerű. Beállítjuk a felbontást és megjelenítjük a szöveget. diff --git a/0A_pcscreenfont/README.md b/0A_pcscreenfont/README.md new file mode 100644 index 00000000..e71b86c2 --- /dev/null +++ b/0A_pcscreenfont/README.md @@ -0,0 +1,31 @@ +Tutorial 0A - PC Screen Font +============================ + +Drawing pixmaps is fun, but definitely there's a need to display characters as well. Basicaly fonts +are nothing more than bitmaps for each character. For this tutorial I choosed PC Screen Font format, +the same Linux Console uses. + +Lfb.h, lfb.c +------------ + +`lfb_init()` sets up resolution, depth, and color channel order. Also queries framebuffer's address. + +`lfb_print(x,y,s)` displays a string on screen. + +Font.psf +-------- + +The font file. Use any file from /usr/share/kbd/consolefonts. Unicode table is not supported. Translating +characters to glyph index using that table (instead of one-to-one relation) is a homework for you. This font +is generated from the original IBM PC VGA 8x16 Font ROM, and includes 127 glyphs. + +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. + +Main +---- + +Very simple. We set the resolution and display the string. diff --git a/0A_pcscreenfont/delays.c b/0A_pcscreenfont/delays.c new file mode 100644 index 00000000..aba77264 --- /dev/null +++ b/0A_pcscreenfont/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(rheadersize + (*((unsigned char*)s)numglyph?*s:0)*font->bytesperglyph; + // calculate the offset on screen + int offs = (y * font->height * pitch) + (x * (font->width+1) * 4); + // variables + int i,j, line,mask, bytesperline=(font->width+7)/8; + // handle carrige return + if(*s=='\r') { + x=0; + } else + // new line + if(*s=='\n') { + x=0; y++; + } else { + // display a character + for(j=0;jheight;j++){ + // display one row + line=offs; + mask=1<<(font->width-1); + for(i=0;iwidth;i++){ + // if bit set, we use white color, otherwise black + *((unsigned int*)(lfb + line))=((int)*glyph) & mask?0xFFFFFF:0; + mask>>=1; + line+=4; + } + // adjust to next line + glyph+=bytesperline; + offs+=pitch; + } + x++; + } + // next character + s++; + } +} diff --git a/0A_pcscreenfont/lfb.h b/0A_pcscreenfont/lfb.h new file mode 100644 index 00000000..411158f3 --- /dev/null +++ b/0A_pcscreenfont/lfb.h @@ -0,0 +1,27 @@ +/* + * 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 lfb_init(); +void lfb_print(int x, int y, char *s); diff --git a/0A_pcscreenfont/link.ld b/0A_pcscreenfont/link.ld new file mode 100644 index 00000000..1352bfb1 --- /dev/null +++ b/0A_pcscreenfont/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/0A_pcscreenfont/main.c b/0A_pcscreenfont/main.c new file mode 100644 index 00000000..2ed80db0 --- /dev/null +++ b/0A_pcscreenfont/main.c @@ -0,0 +1,42 @@ +/* + * 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 "lfb.h" + +void main() +{ + // set up serial console and linear frame buffer + uart_init(); + lfb_init(); + + // display a string on screen + lfb_print(10, 5, "Hello World!"); + + // echo everything back + while(1) { + uart_send(uart_getc()); + } +} diff --git a/0A_pcscreenfont/mbox.c b/0A_pcscreenfont/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/0A_pcscreenfont/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/0A_pcscreenfont/mbox.h b/0A_pcscreenfont/mbox.h new file mode 100644 index 00000000..8408d275 --- /dev/null +++ b/0A_pcscreenfont/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/0A_pcscreenfont/start.S b/0A_pcscreenfont/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/0A_pcscreenfont/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/0A_pcscreenfont/uart.c b/0A_pcscreenfont/uart.c new file mode 100644 index 00000000..55fef794 --- /dev/null +++ b/0A_pcscreenfont/uart.c @@ -0,0 +1,127 @@ +/* + * 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 carachter 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/0A_pcscreenfont/uart.h b/0A_pcscreenfont/uart.h new file mode 100644 index 00000000..99b2be48 --- /dev/null +++ b/0A_pcscreenfont/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/0B_readsector/Makefile b/0B_readsector/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/0B_readsector/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/0B_readsector/OLVASSEL.md b/0B_readsector/OLVASSEL.md new file mode 100644 index 00000000..a9116d55 --- /dev/null +++ b/0B_readsector/OLVASSEL.md @@ -0,0 +1,22 @@ +Oktatóanyag 0B - Szektor Beolvasás +================================== + +Ezidáig minden adatot (kép, font) hozzálinkeltünk a kernelhez. Itt az ideje, hogy adatot olvassunk be +az SD kártyáról. Ebben az oktatóanyagban egy igazi meghajtót implementálunk a szektor beolvasásához. + +Sd.h, sd.c +------------ + +Nos, jó lenne, ha lenne levelesláda szektorok olvasására és írására, de nincs. Ezért nekünk kell direktben +beszélni az EMMC-vel, ami trükkös és unalmas feladat. Különböző kártyákkal is törődnünk kell. De végül, +rendelkezésre áll két funkció. + +`sd_init()` inicializálja az EMMC-t SD kártya olvasáshoz. + +`sd_readblock(lba,buffer,num)` beolvas num blokkot (szektort) az SD kártyáról a buffer-be lba-tól kezdve. + +Main +---- + +A blokkot a bss szegmens utánra töltjük be, majd kidumpoljuk a konzolra. A beolvasás funkció részletes +üzeneteket ír ki arról, hogy épp mit kommunikál az EMMC vezérlővel. diff --git a/0B_readsector/README.md b/0B_readsector/README.md new file mode 100644 index 00000000..f6ce6c67 --- /dev/null +++ b/0B_readsector/README.md @@ -0,0 +1,22 @@ +Tutorial 0B - Read Sector +========================= + +So far we have linked our data (pixmap, font) to the kernel image. It is time to read data from the +SD card. For this tutorial we're implementing a real driver for read sector function. + +Sd.h, sd.c +------------ + +Well, it would be nice to have a mailbox for reading and writing sectors, but there isn't. So we have to +talk directly to the EMMC, which is tricky and boring. We have to handle all kinds of cards. But finally, +we have two function. + +`sd_init()` initialize EMMC for SD card read. + +`sd_readblock(lba,buffer,num)` read num blocks (sectors) from the SD card into buffer starting at sector lba. + +Main +---- + +We read a block after the bss segment in memory, and then we dump it to the console. The read function will +display detailed information on the EMMC communication. diff --git a/0B_readsector/delays.c b/0B_readsector/delays.c new file mode 100644 index 00000000..aba77264 --- /dev/null +++ b/0B_readsector/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(r>3; diff --git a/0B_readsector/main.c b/0B_readsector/main.c new file mode 100644 index 00000000..c090dbd8 --- /dev/null +++ b/0B_readsector/main.c @@ -0,0 +1,50 @@ +/* + * 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 "sd.h" + +// get the end of bss segment from linker +extern unsigned char _end; + +void main() +{ + // set up serial console + uart_init(); + + // initialize EMMC and detect SD card type + if(sd_init()==SD_OK) { + // read the master boot record after our bss segment + if(sd_readblock(0,&_end,1)) { + // dump it to serial console + uart_dump(&_end); + } + } + + // echo everything back + while(1) { + uart_send(uart_getc()); + } +} diff --git a/0B_readsector/mbox.c b/0B_readsector/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/0B_readsector/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/0B_readsector/mbox.h b/0B_readsector/mbox.h new file mode 100644 index 00000000..8408d275 --- /dev/null +++ b/0B_readsector/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/0B_readsector/sd.c b/0B_readsector/sd.c new file mode 100644 index 00000000..3d9f8183 --- /dev/null +++ b/0B_readsector/sd.c @@ -0,0 +1,355 @@ +/* + * 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 "uart.h" +#include "delays.h" +#include "sd.h" + +#define EMMC_ARG2 ((volatile unsigned int*)(MMIO_BASE+0x00300000)) +#define EMMC_BLKSIZECNT ((volatile unsigned int*)(MMIO_BASE+0x00300004)) +#define EMMC_ARG1 ((volatile unsigned int*)(MMIO_BASE+0x00300008)) +#define EMMC_CMDTM ((volatile unsigned int*)(MMIO_BASE+0x0030000C)) +#define EMMC_RESP0 ((volatile unsigned int*)(MMIO_BASE+0x00300010)) +#define EMMC_RESP1 ((volatile unsigned int*)(MMIO_BASE+0x00300014)) +#define EMMC_RESP2 ((volatile unsigned int*)(MMIO_BASE+0x00300018)) +#define EMMC_RESP3 ((volatile unsigned int*)(MMIO_BASE+0x0030001C)) +#define EMMC_DATA ((volatile unsigned int*)(MMIO_BASE+0x00300020)) +#define EMMC_STATUS ((volatile unsigned int*)(MMIO_BASE+0x00300024)) +#define EMMC_CONTROL0 ((volatile unsigned int*)(MMIO_BASE+0x00300028)) +#define EMMC_CONTROL1 ((volatile unsigned int*)(MMIO_BASE+0x0030002C)) +#define EMMC_INTERRUPT ((volatile unsigned int*)(MMIO_BASE+0x00300030)) +#define EMMC_INT_MASK ((volatile unsigned int*)(MMIO_BASE+0x00300034)) +#define EMMC_INT_EN ((volatile unsigned int*)(MMIO_BASE+0x00300038)) +#define EMMC_CONTROL2 ((volatile unsigned int*)(MMIO_BASE+0x0030003C)) +#define EMMC_SLOTISR_VER ((volatile unsigned int*)(MMIO_BASE+0x003000FC)) + +// command flags +#define CMD_NEED_APP 0x80000000 +#define CMD_RSPNS_48 0x00020000 +#define CMD_ERRORS_MASK 0xfff9c004 +#define CMD_RCA_MASK 0xffff0000 + +// COMMANDs +#define CMD_GO_IDLE 0x00000000 +#define CMD_ALL_SEND_CID 0x02010000 +#define CMD_SEND_REL_ADDR 0x03020000 +#define CMD_CARD_SELECT 0x07030000 +#define CMD_SEND_IF_COND 0x08020000 +#define CMD_STOP_TRANS 0x0C030000 +#define CMD_READ_SINGLE 0x11220010 +#define CMD_READ_MULTI 0x12220032 +#define CMD_SET_BLOCKCNT 0x17020000 +#define CMD_APP_CMD 0x37000000 +#define CMD_SET_BUS_WIDTH (0x06020000|CMD_NEED_APP) +#define CMD_SEND_OP_COND (0x29020000|CMD_NEED_APP) +#define CMD_SEND_SCR (0x33220010|CMD_NEED_APP) + +// STATUS register settings +#define SR_READ_AVAILABLE 0x00000800 +#define SR_DAT_INHIBIT 0x00000002 +#define SR_CMD_INHIBIT 0x00000001 +#define SR_APP_CMD 0x00000020 + +// INTERRUPT register settings +#define INT_DATA_TIMEOUT 0x00100000 +#define INT_CMD_TIMEOUT 0x00010000 +#define INT_READ_RDY 0x00000020 +#define INT_CMD_DONE 0x00000001 + +#define INT_ERROR_MASK 0x017E8000 + +// CONTROL register settings +#define C0_SPI_MODE_EN 0x00100000 +#define C0_HCTL_HS_EN 0x00000004 +#define C0_HCTL_DWITDH 0x00000002 + +#define C1_SRST_DATA 0x04000000 +#define C1_SRST_CMD 0x02000000 +#define C1_SRST_HC 0x01000000 +#define C1_TOUNIT_DIS 0x000f0000 +#define C1_TOUNIT_MAX 0x000e0000 +#define C1_CLK_GENSEL 0x00000020 +#define C1_CLK_EN 0x00000004 +#define C1_CLK_STABLE 0x00000002 +#define C1_CLK_INTLEN 0x00000001 + +// SLOTISR_VER values +#define HOST_SPEC_NUM 0x00ff0000 +#define HOST_SPEC_NUM_SHIFT 16 +#define HOST_SPEC_V3 2 +#define HOST_SPEC_V2 1 +#define HOST_SPEC_V1 0 + +// SCR flags +#define SCR_SD_BUS_WIDTH_4 0x00000400 +#define SCR_SUPP_SET_BLKCNT 0x02000000 +// added by my driver +#define SCR_SUPP_CCS 0x00000001 + +#define ACMD41_VOLTAGE 0x00ff8000 +#define ACMD41_CMD_COMPLETE 0x80000000 +#define ACMD41_CMD_CCS 0x40000000 +#define ACMD41_ARG_HC 0x51ff8000 + +unsigned long sd_scr[2], sd_ocr, sd_rca, sd_err, sd_hv; + +/** + * Wait for data or command ready + */ +int sd_status(unsigned int mask) +{ + int cnt = 500000; while((*EMMC_STATUS & mask) && !(*EMMC_INTERRUPT & INT_ERROR_MASK) && cnt--) wait_msec(1); + return (cnt <= 0 || (*EMMC_INTERRUPT & INT_ERROR_MASK)) ? SD_ERROR : SD_OK; +} + +/** + * Wait for interrupt + */ +int sd_int(unsigned int mask) +{ + unsigned int r, m=mask | INT_ERROR_MASK; + int cnt = 1000000; while(!(*EMMC_INTERRUPT & m) && cnt--) wait_msec(1); + r=*EMMC_INTERRUPT; + if(cnt<=0 || (r & INT_CMD_TIMEOUT) || (r & INT_DATA_TIMEOUT) ) { *EMMC_INTERRUPT=r; return SD_TIMEOUT; } else + if(r & INT_ERROR_MASK) { *EMMC_INTERRUPT=r; return SD_ERROR; } + *EMMC_INTERRUPT=mask; + return 0; +} + +/** + * Send a command + */ +int sd_cmd(unsigned int code, unsigned int arg) +{ + int r=0; + sd_err=SD_OK; + if(code&CMD_NEED_APP) { + r=sd_cmd(CMD_APP_CMD|(sd_rca?CMD_RSPNS_48:0),sd_rca); + if(sd_rca && !r) { uart_puts("ERROR: failed to send SD APP command\n"); sd_err=SD_ERROR;return 0;} + code &= ~CMD_NEED_APP; + } + if(sd_status(SR_CMD_INHIBIT)) { uart_puts("ERROR: EMMC busy\n"); sd_err= SD_TIMEOUT;return 0;} + uart_puts("EMMC: Sending command ");uart_hex(code);uart_puts(" arg ");uart_hex(arg);uart_send('\n'); + *EMMC_INTERRUPT=*EMMC_INTERRUPT; *EMMC_ARG1=arg; *EMMC_CMDTM=code; + if(code==CMD_SEND_OP_COND) wait_msec(1000); else + if(code==CMD_SEND_IF_COND || code==CMD_APP_CMD) wait_msec(100); + if((r=sd_int(INT_CMD_DONE))) {uart_puts("ERROR: failed to send EMMC command\n");sd_err=r;return 0;} + r=*EMMC_RESP0; + if(code==CMD_GO_IDLE || code==CMD_APP_CMD) return 0; else + if(code==(CMD_APP_CMD|CMD_RSPNS_48)) return r&SR_APP_CMD; else + if(code==CMD_SEND_OP_COND) return r; else + if(code==CMD_SEND_IF_COND) return r==arg? SD_OK : SD_ERROR; else + if(code==CMD_ALL_SEND_CID) {r|=*EMMC_RESP3; r|=*EMMC_RESP2; r|=*EMMC_RESP1; return r; } else + if(code==CMD_SEND_REL_ADDR) { + sd_err=(((r&0x1fff))|((r&0x2000)<<6)|((r&0x4000)<<8)|((r&0x8000)<<8))&CMD_ERRORS_MASK; + return r&CMD_RCA_MASK; + } + return r&CMD_ERRORS_MASK; + // make gcc happy + return 0; +} + +/** + * read a block from sd card and return the number of bytes read + * returns 0 on error. + */ +int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num) +{ + int r,c=0,d; + if(num<1) num=1; + uart_puts("sd_readblock lba ");uart_hex(lba);uart_puts(" num ");uart_hex(num);uart_send('\n'); + if(sd_status(SR_DAT_INHIBIT)) {sd_err=SD_TIMEOUT; return 0;} + unsigned int *buf=(unsigned int *)buffer; + if(sd_scr[0] & SCR_SUPP_CCS) { + if(num > 1 && (sd_scr[0] & SCR_SUPP_SET_BLKCNT)) { + sd_cmd(CMD_SET_BLOCKCNT,num); + if(sd_err) return 0; + } + *EMMC_BLKSIZECNT = (num << 16) | 512; + sd_cmd(num == 1 ? CMD_READ_SINGLE : CMD_READ_MULTI,lba); + if(sd_err) return 0; + } else { + *EMMC_BLKSIZECNT = (1 << 16) | 512; + } + while( c < num ) { + if(!(sd_scr[0] & SCR_SUPP_CCS)) { + sd_cmd(CMD_READ_SINGLE,(lba+c)*512); + if(sd_err) return 0; + } + if((r=sd_int(INT_READ_RDY))){uart_puts("\rERROR: Timeout waiting for ready to read\n");sd_err=r;return 0;} + for(d=0;d<128;d++) buf[d] = *EMMC_DATA; + c++; buf+=128; + } + if( num > 1 && !(sd_scr[0] & SCR_SUPP_SET_BLKCNT) && (sd_scr[0] & SCR_SUPP_CCS)) sd_cmd(CMD_STOP_TRANS,0); + return sd_err!=SD_OK || c!=num? 0 : num*512; +} + +/** + * set SD clock to frequency in Hz + */ +int sd_clk(unsigned int f) +{ + unsigned int d,c=41666666/f,x,s=32,h=0; + int cnt = 100000; + while((*EMMC_STATUS & (SR_CMD_INHIBIT|SR_DAT_INHIBIT)) && cnt--) wait_msec(1); + if(cnt<=0) { + uart_puts("ERROR: timeout waiting for inhibit flag\n"); + return SD_ERROR; + } + + *EMMC_CONTROL1 &= ~C1_CLK_EN; wait_msec(10); + x=c-1; if(!x) s=0; else { + if(!(x & 0xffff0000u)) { x <<= 16; s -= 16; } + if(!(x & 0xff000000u)) { x <<= 8; s -= 8; } + if(!(x & 0xf0000000u)) { x <<= 4; s -= 4; } + if(!(x & 0xc0000000u)) { x <<= 2; s -= 2; } + if(!(x & 0x80000000u)) { x <<= 1; s -= 1; } + if(s>0) s--; + if(s>7) s=7; + } + if(sd_hv>HOST_SPEC_V2) d=c; else d=(1<HOST_SPEC_V2) h=(d&0x300)>>2; + d=(((d&0x0ff)<<8)|h); + *EMMC_CONTROL1=(*EMMC_CONTROL1&0xffff003f)|d; wait_msec(10); + *EMMC_CONTROL1 |= C1_CLK_EN; wait_msec(10); + cnt=10000; while(!(*EMMC_CONTROL1 & C1_CLK_STABLE) && cnt--) wait_msec(10); + if(cnt<=0) { + uart_puts("ERROR: failed to get stable clock\n"); + return SD_ERROR; + } + return SD_OK; +} + +/** + * initialize EMMC to read SDHC card + */ +int sd_init() +{ + long r,cnt,ccs=0; + // GPIO_CD + r=*GPFSEL4; r&=~(7<<(7*3)); *GPFSEL4=r; + *GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<15); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; + r=*GPHEN1; r|=1<<15; *GPHEN1=r; + + // GPIO_CLK, GPIO_CMD + r=*GPFSEL4; r|=(7<<(8*3))|(7<<(9*3)); *GPFSEL4=r; + *GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<16)|(1<<17); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; + + // GPIO_DAT0, GPIO_DAT1, GPIO_DAT2, GPIO_DAT3 + r=*GPFSEL5; r|=(7<<(0*3)) | (7<<(1*3)) | (7<<(2*3)) | (7<<(3*3)); *GPFSEL5=r; + *GPPUD=2; wait_cycles(150); + *GPPUDCLK1=(1<<18) | (1<<19) | (1<<20) | (1<<21); + wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; + + sd_hv = (*EMMC_SLOTISR_VER & HOST_SPEC_NUM) >> HOST_SPEC_NUM_SHIFT; + uart_puts("EMMC: GPIO set up\n"); + // Reset the card. + *EMMC_CONTROL0 = 0; *EMMC_CONTROL1 |= C1_SRST_HC; + cnt=10000; do{wait_msec(10);} while( (*EMMC_CONTROL1 & C1_SRST_HC) && cnt-- ); + if(cnt<=0) { + uart_puts("ERROR: failed to reset EMMC\n"); + return SD_ERROR; + } + uart_puts("EMMC: reset OK\n"); + *EMMC_CONTROL1 |= C1_CLK_INTLEN | C1_TOUNIT_MAX; + wait_msec(10); + // Set clock to setup frequency. + if((r=sd_clk(400000))) return r; + *EMMC_INT_EN = 0xffffffff; + *EMMC_INT_MASK = 0xffffffff; + sd_scr[0]=sd_scr[1]=sd_rca=sd_err=0; + sd_cmd(CMD_GO_IDLE,0); + if(sd_err) return sd_err; + + sd_cmd(CMD_SEND_IF_COND,0x000001AA); + if(sd_err) return sd_err; + cnt=6; r=0; while(!(r&ACMD41_CMD_COMPLETE) && cnt--) { + wait_cycles(400); + r=sd_cmd(CMD_SEND_OP_COND,ACMD41_ARG_HC); + uart_puts("EMMC: CMD_SEND_OP_COND returned "); + if(r&ACMD41_CMD_COMPLETE) + uart_puts("COMPLETE "); + if(r&ACMD41_VOLTAGE) + uart_puts("VOLTAGE "); + if(r&ACMD41_CMD_CCS) + uart_puts("CCS "); + uart_hex(r>>32); + uart_hex(r); + uart_send('\n'); + if(sd_err!=SD_TIMEOUT && sd_err!=SD_OK ) { + uart_puts("ERROR: EMMC ACMD41 returned error\n"); + return sd_err; + } + } + if(!(r&ACMD41_CMD_COMPLETE) || !cnt ) return SD_TIMEOUT; + if(!(r&ACMD41_VOLTAGE)) return SD_ERROR; + if(r&ACMD41_CMD_CCS) ccs=SCR_SUPP_CCS; + + sd_cmd(CMD_ALL_SEND_CID,0); + + sd_rca = sd_cmd(CMD_SEND_REL_ADDR,0); + uart_puts("EMMC: CMD_SEND_REL_ADDR returned "); + uart_hex(sd_rca>>32); + uart_hex(sd_rca); + uart_send('\n'); + if(sd_err) return sd_err; + + if((r=sd_clk(25000000))) return r; + + sd_cmd(CMD_CARD_SELECT,sd_rca); + if(sd_err) return sd_err; + + if(sd_status(SR_DAT_INHIBIT)) return SD_TIMEOUT; + *EMMC_BLKSIZECNT = (1<<16) | 8; + sd_cmd(CMD_SEND_SCR,0); + if(sd_err) return sd_err; + if(sd_int(INT_READ_RDY)) return SD_TIMEOUT; + + r=0; cnt=100000; while(r<2 && cnt) { + if( *EMMC_STATUS & SR_READ_AVAILABLE ) + sd_scr[r++] = *EMMC_DATA; + else + wait_msec(1); + } + if(r!=2) return SD_TIMEOUT; + if(sd_scr[0] & SCR_SD_BUS_WIDTH_4) { + sd_cmd(CMD_SET_BUS_WIDTH,sd_rca|2); + if(sd_err) return sd_err; + *EMMC_CONTROL0 |= C0_HCTL_DWITDH; + } + // add software flag + uart_puts("EMMC: supports "); + if(sd_scr[0] & SCR_SUPP_SET_BLKCNT) + uart_puts("SET_BLKCNT "); + if(ccs) + uart_puts("CCS "); + uart_send('\n'); + sd_scr[0]&=~SCR_SUPP_CCS; + sd_scr[0]|=ccs; + return SD_OK; +} diff --git a/0B_readsector/sd.h b/0B_readsector/sd.h new file mode 100644 index 00000000..5325a320 --- /dev/null +++ b/0B_readsector/sd.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. + * + */ + +#define SD_OK 0 +#define SD_TIMEOUT -1 +#define SD_ERROR -2 + +int sd_init(); +int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num); diff --git a/0B_readsector/start.S b/0B_readsector/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/0B_readsector/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/0B_readsector/uart.c b/0B_readsector/uart.c new file mode 100644 index 00000000..8297d9ff --- /dev/null +++ b/0B_readsector/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 carachter 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/0B_readsector/uart.h b/0B_readsector/uart.h new file mode 100644 index 00000000..f74e5263 --- /dev/null +++ b/0B_readsector/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/0C_directory/Makefile b/0C_directory/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/0C_directory/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/0C_directory/OLVASSEL.md b/0C_directory/OLVASSEL.md new file mode 100644 index 00000000..27abbd76 --- /dev/null +++ b/0C_directory/OLVASSEL.md @@ -0,0 +1,42 @@ +Oktatóanyag 0C - Könyvtárak +=========================== + +Most hogy már tudunk szektort beolvasni, ideje értelmezni a fájlrendszert. Ez az oktatóanyag megtanítja, +hogy hogyan listázzuk ki egy FAT16 vagy FAT32 partíció gyökérkönyvtárát. + +```sh +$ qemu-system-aarch64 -M raspi3 -drive file=test.dd,if=sd,format=raw -serial stdio + ... kimenet törölve az átláthatóság miatt ... +MBR disk identifier: 12345678 +FAT partition starts at: 00000008 + ... kimenet törölve az átláthatóság miatt ... +FAT type: FAT16 +FAT number of root diretory entries: 00000200 +FAT root directory LBA: 00000034 + ... kimenet törölve az átláthatóság miatt ... +Attrib Cluster Size Name +...L.. 00000000 00000000 EFI System +....D. 00000003 00000000 FOLDER +.....A 00000171 0000C448 BOOTCODEBIN +.....A 0000018A 000019B3 FIXUP DAT +.....A 0000018E 00001B10 KERNEL8 IMG +.....A 00000192 000005D6 LICENC~1BRO +.....A 00000193 002B2424 START ELF +``` + +Fat.h, fat.c +------------ + +Ez elég egyszerű és jól dokumentált művelet. Beolvassuk az MBR-t, megkeressük a partíciónkat, majd +betöltjük az első szektorát (Volume Boot Record). Ebben van az ún. BIOS Parameter Block, ami leírja +a FAT fájlrendszert. + +`fat_getpartition()` betölti és értelmezi a partíció első szektorát. + +`fat_listdirectory()` kilistázza a fájlrendszer gyökérkönyvtárának tartalmát. + +Main +---- + +Miután inicializájuk az EMMC-t szektorok olvasásához, beolvassuk az első szektort a partícióról. Ha a BPB +egy érvényes FAT fájlrendszert ír le, akkor kilistázzuk a fájlrendszer gyükérkönyvtárát. diff --git a/0C_directory/README.md b/0C_directory/README.md new file mode 100644 index 00000000..7b703c01 --- /dev/null +++ b/0C_directory/README.md @@ -0,0 +1,42 @@ +Tutorial 0C - Directory +======================= + +Now that we can load a sector from the storage, it is time to parse it as a file system. This +tutorial will show you how to list the root directory entries of a FAT16 or FAT32 partition. + +```sh +$ qemu-system-aarch64 -M raspi3 -drive file=test.dd,if=sd,format=raw -serial stdio + ... output removed for clearity ... +MBR disk identifier: 12345678 +FAT partition starts at: 00000008 + ... output removed for clearity ... +FAT type: FAT16 +FAT number of root diretory entries: 00000200 +FAT root directory LBA: 00000034 + ... output removed for clearity ... +Attrib Cluster Size Name +...L.. 00000000 00000000 EFI System +....D. 00000003 00000000 FOLDER +.....A 00000171 0000C448 BOOTCODEBIN +.....A 0000018A 000019B3 FIXUP DAT +.....A 0000018E 00001B10 KERNEL8 IMG +.....A 00000192 000005D6 LICENC~1BRO +.....A 00000193 002B2424 START ELF +``` + +Fat.h, fat.c +------------ + +This is easy and pretty well documented. We have to read the MBR, locate our partition, and load +it's first sector (Volume Boot Record). That has the BIOS Parameter Block, which describes the FAT +file system. + +`fat_getpartition()` load and check the boot record of the first MBR partition. + +`fat_listdirectory()` list root directory entries on the volume. + +Main +---- + +Once we initialize EMMC to read sectors, we load the boot record of the first partition. If the BPB +describes a valid FAT partition, we list the root directory entries in it. diff --git a/0C_directory/delays.c b/0C_directory/delays.c new file mode 100644 index 00000000..aba77264 --- /dev/null +++ b/0C_directory/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(rfst[0]=='F' && bpb->fst[1]=='A' && bpb->fst[2]=='T') && + !(bpb->fst2[0]=='F' && bpb->fst2[1]=='A' && bpb->fst2[2]=='T')) { + uart_puts("ERROR: Unknown file system type\n"); + return 0; + } + uart_puts("FAT type: "); + // if 16 bit sector per fat is zero, then it's a FAT32 + uart_puts(bpb->spf16>0?"FAT16":"FAT32"); + uart_puts("\n"); + return 1; + } + return 0; +} + +/** + * List root directory entries in a FAT file system + */ +void fat_listdirectory() +{ + bpb_t *bpb=(bpb_t*)&_end; + fatdir_t *dir=(fatdir_t*)&_end; + unsigned int root_sec, s; + // find the root directory's LBA + root_sec=((bpb->spf16?bpb->spf16:bpb->spf32)*bpb->nf)+bpb->rsc; + //WARNING gcc generates bad code for bpb->nr, causing unaligned exception + s=*((unsigned int*)&bpb->nf); + s>>=8; + s&=0xFFFF; + uart_puts("FAT number of root diretory entries: "); + uart_hex(s); + s<<=5; + // now s=bpb->nr*sizeof(fatdir_t)); + if(bpb->spf16==0) { + // adjust for FAT32 + root_sec+=(bpb->rc-2)*bpb->spc; + } + // add partition LBA + root_sec+=partitionlba; + uart_puts("\nFAT root directory LBA: "); + uart_hex(root_sec); + uart_puts("\n"); + // load the root directory + if(sd_readblock(root_sec,(unsigned char*)&_end,s/512+1)) { + uart_puts("\nAttrib Cluster Size Name\n"); + // iterate on each entry and print out + for(;dir->name[0]!=0;dir++) { + // is it a valid entry? + if(dir->name[0]==0xE5 || dir->attr[0]==0xF) continue; + // decode attributes + uart_send(dir->attr[0]& 1?'R':'.'); // read-only + uart_send(dir->attr[0]& 2?'H':'.'); // hidden + uart_send(dir->attr[0]& 4?'S':'.'); // system + uart_send(dir->attr[0]& 8?'L':'.'); // volume label + uart_send(dir->attr[0]&16?'D':'.'); // directory + uart_send(dir->attr[0]&32?'A':'.'); // archive + uart_send(' '); + // staring cluster + uart_hex(((unsigned int)dir->ch)<<16|dir->cl); + uart_send(' '); + // size + uart_hex(dir->size); + uart_send(' '); + // filename + dir->attr[0]=0; + uart_puts(dir->name); + uart_puts("\n"); + } + } else { + uart_puts("ERROR: Unable to load root directory\n"); + } +} diff --git a/0C_directory/fat.h b/0C_directory/fat.h new file mode 100644 index 00000000..e31baddd --- /dev/null +++ b/0C_directory/fat.h @@ -0,0 +1,27 @@ +/* + * 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. + * + */ + +int fat_getpartition(); +void fat_listdirectory(); diff --git a/0C_directory/gpio.h b/0C_directory/gpio.h new file mode 100644 index 00000000..52fa671d --- /dev/null +++ b/0C_directory/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/0C_directory/kernel8.img b/0C_directory/kernel8.img new file mode 100755 index 00000000..3716b912 Binary files /dev/null and b/0C_directory/kernel8.img differ diff --git a/0C_directory/link.ld b/0C_directory/link.ld new file mode 100644 index 00000000..1352bfb1 --- /dev/null +++ b/0C_directory/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/0C_directory/main.c b/0C_directory/main.c new file mode 100644 index 00000000..a29fcaa5 --- /dev/null +++ b/0C_directory/main.c @@ -0,0 +1,50 @@ +/* + * 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 "sd.h" +#include "fat.h" + +void main() +{ + // set up serial console + uart_init(); + + // initialize EMMC and detect SD card type + if(sd_init()==SD_OK) { + // read the master boot record and find our partition + if(fat_getpartition()) { + // list root directory entries + fat_listdirectory(); + } else { + uart_puts("FAT partition not found???\n"); + } + } + + // echo everything back + while(1) { + uart_send(uart_getc()); + } +} diff --git a/0C_directory/mbox.c b/0C_directory/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/0C_directory/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/0C_directory/mbox.h b/0C_directory/mbox.h new file mode 100644 index 00000000..8408d275 --- /dev/null +++ b/0C_directory/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/0C_directory/sd.c b/0C_directory/sd.c new file mode 100644 index 00000000..3d9f8183 --- /dev/null +++ b/0C_directory/sd.c @@ -0,0 +1,355 @@ +/* + * 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 "uart.h" +#include "delays.h" +#include "sd.h" + +#define EMMC_ARG2 ((volatile unsigned int*)(MMIO_BASE+0x00300000)) +#define EMMC_BLKSIZECNT ((volatile unsigned int*)(MMIO_BASE+0x00300004)) +#define EMMC_ARG1 ((volatile unsigned int*)(MMIO_BASE+0x00300008)) +#define EMMC_CMDTM ((volatile unsigned int*)(MMIO_BASE+0x0030000C)) +#define EMMC_RESP0 ((volatile unsigned int*)(MMIO_BASE+0x00300010)) +#define EMMC_RESP1 ((volatile unsigned int*)(MMIO_BASE+0x00300014)) +#define EMMC_RESP2 ((volatile unsigned int*)(MMIO_BASE+0x00300018)) +#define EMMC_RESP3 ((volatile unsigned int*)(MMIO_BASE+0x0030001C)) +#define EMMC_DATA ((volatile unsigned int*)(MMIO_BASE+0x00300020)) +#define EMMC_STATUS ((volatile unsigned int*)(MMIO_BASE+0x00300024)) +#define EMMC_CONTROL0 ((volatile unsigned int*)(MMIO_BASE+0x00300028)) +#define EMMC_CONTROL1 ((volatile unsigned int*)(MMIO_BASE+0x0030002C)) +#define EMMC_INTERRUPT ((volatile unsigned int*)(MMIO_BASE+0x00300030)) +#define EMMC_INT_MASK ((volatile unsigned int*)(MMIO_BASE+0x00300034)) +#define EMMC_INT_EN ((volatile unsigned int*)(MMIO_BASE+0x00300038)) +#define EMMC_CONTROL2 ((volatile unsigned int*)(MMIO_BASE+0x0030003C)) +#define EMMC_SLOTISR_VER ((volatile unsigned int*)(MMIO_BASE+0x003000FC)) + +// command flags +#define CMD_NEED_APP 0x80000000 +#define CMD_RSPNS_48 0x00020000 +#define CMD_ERRORS_MASK 0xfff9c004 +#define CMD_RCA_MASK 0xffff0000 + +// COMMANDs +#define CMD_GO_IDLE 0x00000000 +#define CMD_ALL_SEND_CID 0x02010000 +#define CMD_SEND_REL_ADDR 0x03020000 +#define CMD_CARD_SELECT 0x07030000 +#define CMD_SEND_IF_COND 0x08020000 +#define CMD_STOP_TRANS 0x0C030000 +#define CMD_READ_SINGLE 0x11220010 +#define CMD_READ_MULTI 0x12220032 +#define CMD_SET_BLOCKCNT 0x17020000 +#define CMD_APP_CMD 0x37000000 +#define CMD_SET_BUS_WIDTH (0x06020000|CMD_NEED_APP) +#define CMD_SEND_OP_COND (0x29020000|CMD_NEED_APP) +#define CMD_SEND_SCR (0x33220010|CMD_NEED_APP) + +// STATUS register settings +#define SR_READ_AVAILABLE 0x00000800 +#define SR_DAT_INHIBIT 0x00000002 +#define SR_CMD_INHIBIT 0x00000001 +#define SR_APP_CMD 0x00000020 + +// INTERRUPT register settings +#define INT_DATA_TIMEOUT 0x00100000 +#define INT_CMD_TIMEOUT 0x00010000 +#define INT_READ_RDY 0x00000020 +#define INT_CMD_DONE 0x00000001 + +#define INT_ERROR_MASK 0x017E8000 + +// CONTROL register settings +#define C0_SPI_MODE_EN 0x00100000 +#define C0_HCTL_HS_EN 0x00000004 +#define C0_HCTL_DWITDH 0x00000002 + +#define C1_SRST_DATA 0x04000000 +#define C1_SRST_CMD 0x02000000 +#define C1_SRST_HC 0x01000000 +#define C1_TOUNIT_DIS 0x000f0000 +#define C1_TOUNIT_MAX 0x000e0000 +#define C1_CLK_GENSEL 0x00000020 +#define C1_CLK_EN 0x00000004 +#define C1_CLK_STABLE 0x00000002 +#define C1_CLK_INTLEN 0x00000001 + +// SLOTISR_VER values +#define HOST_SPEC_NUM 0x00ff0000 +#define HOST_SPEC_NUM_SHIFT 16 +#define HOST_SPEC_V3 2 +#define HOST_SPEC_V2 1 +#define HOST_SPEC_V1 0 + +// SCR flags +#define SCR_SD_BUS_WIDTH_4 0x00000400 +#define SCR_SUPP_SET_BLKCNT 0x02000000 +// added by my driver +#define SCR_SUPP_CCS 0x00000001 + +#define ACMD41_VOLTAGE 0x00ff8000 +#define ACMD41_CMD_COMPLETE 0x80000000 +#define ACMD41_CMD_CCS 0x40000000 +#define ACMD41_ARG_HC 0x51ff8000 + +unsigned long sd_scr[2], sd_ocr, sd_rca, sd_err, sd_hv; + +/** + * Wait for data or command ready + */ +int sd_status(unsigned int mask) +{ + int cnt = 500000; while((*EMMC_STATUS & mask) && !(*EMMC_INTERRUPT & INT_ERROR_MASK) && cnt--) wait_msec(1); + return (cnt <= 0 || (*EMMC_INTERRUPT & INT_ERROR_MASK)) ? SD_ERROR : SD_OK; +} + +/** + * Wait for interrupt + */ +int sd_int(unsigned int mask) +{ + unsigned int r, m=mask | INT_ERROR_MASK; + int cnt = 1000000; while(!(*EMMC_INTERRUPT & m) && cnt--) wait_msec(1); + r=*EMMC_INTERRUPT; + if(cnt<=0 || (r & INT_CMD_TIMEOUT) || (r & INT_DATA_TIMEOUT) ) { *EMMC_INTERRUPT=r; return SD_TIMEOUT; } else + if(r & INT_ERROR_MASK) { *EMMC_INTERRUPT=r; return SD_ERROR; } + *EMMC_INTERRUPT=mask; + return 0; +} + +/** + * Send a command + */ +int sd_cmd(unsigned int code, unsigned int arg) +{ + int r=0; + sd_err=SD_OK; + if(code&CMD_NEED_APP) { + r=sd_cmd(CMD_APP_CMD|(sd_rca?CMD_RSPNS_48:0),sd_rca); + if(sd_rca && !r) { uart_puts("ERROR: failed to send SD APP command\n"); sd_err=SD_ERROR;return 0;} + code &= ~CMD_NEED_APP; + } + if(sd_status(SR_CMD_INHIBIT)) { uart_puts("ERROR: EMMC busy\n"); sd_err= SD_TIMEOUT;return 0;} + uart_puts("EMMC: Sending command ");uart_hex(code);uart_puts(" arg ");uart_hex(arg);uart_send('\n'); + *EMMC_INTERRUPT=*EMMC_INTERRUPT; *EMMC_ARG1=arg; *EMMC_CMDTM=code; + if(code==CMD_SEND_OP_COND) wait_msec(1000); else + if(code==CMD_SEND_IF_COND || code==CMD_APP_CMD) wait_msec(100); + if((r=sd_int(INT_CMD_DONE))) {uart_puts("ERROR: failed to send EMMC command\n");sd_err=r;return 0;} + r=*EMMC_RESP0; + if(code==CMD_GO_IDLE || code==CMD_APP_CMD) return 0; else + if(code==(CMD_APP_CMD|CMD_RSPNS_48)) return r&SR_APP_CMD; else + if(code==CMD_SEND_OP_COND) return r; else + if(code==CMD_SEND_IF_COND) return r==arg? SD_OK : SD_ERROR; else + if(code==CMD_ALL_SEND_CID) {r|=*EMMC_RESP3; r|=*EMMC_RESP2; r|=*EMMC_RESP1; return r; } else + if(code==CMD_SEND_REL_ADDR) { + sd_err=(((r&0x1fff))|((r&0x2000)<<6)|((r&0x4000)<<8)|((r&0x8000)<<8))&CMD_ERRORS_MASK; + return r&CMD_RCA_MASK; + } + return r&CMD_ERRORS_MASK; + // make gcc happy + return 0; +} + +/** + * read a block from sd card and return the number of bytes read + * returns 0 on error. + */ +int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num) +{ + int r,c=0,d; + if(num<1) num=1; + uart_puts("sd_readblock lba ");uart_hex(lba);uart_puts(" num ");uart_hex(num);uart_send('\n'); + if(sd_status(SR_DAT_INHIBIT)) {sd_err=SD_TIMEOUT; return 0;} + unsigned int *buf=(unsigned int *)buffer; + if(sd_scr[0] & SCR_SUPP_CCS) { + if(num > 1 && (sd_scr[0] & SCR_SUPP_SET_BLKCNT)) { + sd_cmd(CMD_SET_BLOCKCNT,num); + if(sd_err) return 0; + } + *EMMC_BLKSIZECNT = (num << 16) | 512; + sd_cmd(num == 1 ? CMD_READ_SINGLE : CMD_READ_MULTI,lba); + if(sd_err) return 0; + } else { + *EMMC_BLKSIZECNT = (1 << 16) | 512; + } + while( c < num ) { + if(!(sd_scr[0] & SCR_SUPP_CCS)) { + sd_cmd(CMD_READ_SINGLE,(lba+c)*512); + if(sd_err) return 0; + } + if((r=sd_int(INT_READ_RDY))){uart_puts("\rERROR: Timeout waiting for ready to read\n");sd_err=r;return 0;} + for(d=0;d<128;d++) buf[d] = *EMMC_DATA; + c++; buf+=128; + } + if( num > 1 && !(sd_scr[0] & SCR_SUPP_SET_BLKCNT) && (sd_scr[0] & SCR_SUPP_CCS)) sd_cmd(CMD_STOP_TRANS,0); + return sd_err!=SD_OK || c!=num? 0 : num*512; +} + +/** + * set SD clock to frequency in Hz + */ +int sd_clk(unsigned int f) +{ + unsigned int d,c=41666666/f,x,s=32,h=0; + int cnt = 100000; + while((*EMMC_STATUS & (SR_CMD_INHIBIT|SR_DAT_INHIBIT)) && cnt--) wait_msec(1); + if(cnt<=0) { + uart_puts("ERROR: timeout waiting for inhibit flag\n"); + return SD_ERROR; + } + + *EMMC_CONTROL1 &= ~C1_CLK_EN; wait_msec(10); + x=c-1; if(!x) s=0; else { + if(!(x & 0xffff0000u)) { x <<= 16; s -= 16; } + if(!(x & 0xff000000u)) { x <<= 8; s -= 8; } + if(!(x & 0xf0000000u)) { x <<= 4; s -= 4; } + if(!(x & 0xc0000000u)) { x <<= 2; s -= 2; } + if(!(x & 0x80000000u)) { x <<= 1; s -= 1; } + if(s>0) s--; + if(s>7) s=7; + } + if(sd_hv>HOST_SPEC_V2) d=c; else d=(1<HOST_SPEC_V2) h=(d&0x300)>>2; + d=(((d&0x0ff)<<8)|h); + *EMMC_CONTROL1=(*EMMC_CONTROL1&0xffff003f)|d; wait_msec(10); + *EMMC_CONTROL1 |= C1_CLK_EN; wait_msec(10); + cnt=10000; while(!(*EMMC_CONTROL1 & C1_CLK_STABLE) && cnt--) wait_msec(10); + if(cnt<=0) { + uart_puts("ERROR: failed to get stable clock\n"); + return SD_ERROR; + } + return SD_OK; +} + +/** + * initialize EMMC to read SDHC card + */ +int sd_init() +{ + long r,cnt,ccs=0; + // GPIO_CD + r=*GPFSEL4; r&=~(7<<(7*3)); *GPFSEL4=r; + *GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<15); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; + r=*GPHEN1; r|=1<<15; *GPHEN1=r; + + // GPIO_CLK, GPIO_CMD + r=*GPFSEL4; r|=(7<<(8*3))|(7<<(9*3)); *GPFSEL4=r; + *GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<16)|(1<<17); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; + + // GPIO_DAT0, GPIO_DAT1, GPIO_DAT2, GPIO_DAT3 + r=*GPFSEL5; r|=(7<<(0*3)) | (7<<(1*3)) | (7<<(2*3)) | (7<<(3*3)); *GPFSEL5=r; + *GPPUD=2; wait_cycles(150); + *GPPUDCLK1=(1<<18) | (1<<19) | (1<<20) | (1<<21); + wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; + + sd_hv = (*EMMC_SLOTISR_VER & HOST_SPEC_NUM) >> HOST_SPEC_NUM_SHIFT; + uart_puts("EMMC: GPIO set up\n"); + // Reset the card. + *EMMC_CONTROL0 = 0; *EMMC_CONTROL1 |= C1_SRST_HC; + cnt=10000; do{wait_msec(10);} while( (*EMMC_CONTROL1 & C1_SRST_HC) && cnt-- ); + if(cnt<=0) { + uart_puts("ERROR: failed to reset EMMC\n"); + return SD_ERROR; + } + uart_puts("EMMC: reset OK\n"); + *EMMC_CONTROL1 |= C1_CLK_INTLEN | C1_TOUNIT_MAX; + wait_msec(10); + // Set clock to setup frequency. + if((r=sd_clk(400000))) return r; + *EMMC_INT_EN = 0xffffffff; + *EMMC_INT_MASK = 0xffffffff; + sd_scr[0]=sd_scr[1]=sd_rca=sd_err=0; + sd_cmd(CMD_GO_IDLE,0); + if(sd_err) return sd_err; + + sd_cmd(CMD_SEND_IF_COND,0x000001AA); + if(sd_err) return sd_err; + cnt=6; r=0; while(!(r&ACMD41_CMD_COMPLETE) && cnt--) { + wait_cycles(400); + r=sd_cmd(CMD_SEND_OP_COND,ACMD41_ARG_HC); + uart_puts("EMMC: CMD_SEND_OP_COND returned "); + if(r&ACMD41_CMD_COMPLETE) + uart_puts("COMPLETE "); + if(r&ACMD41_VOLTAGE) + uart_puts("VOLTAGE "); + if(r&ACMD41_CMD_CCS) + uart_puts("CCS "); + uart_hex(r>>32); + uart_hex(r); + uart_send('\n'); + if(sd_err!=SD_TIMEOUT && sd_err!=SD_OK ) { + uart_puts("ERROR: EMMC ACMD41 returned error\n"); + return sd_err; + } + } + if(!(r&ACMD41_CMD_COMPLETE) || !cnt ) return SD_TIMEOUT; + if(!(r&ACMD41_VOLTAGE)) return SD_ERROR; + if(r&ACMD41_CMD_CCS) ccs=SCR_SUPP_CCS; + + sd_cmd(CMD_ALL_SEND_CID,0); + + sd_rca = sd_cmd(CMD_SEND_REL_ADDR,0); + uart_puts("EMMC: CMD_SEND_REL_ADDR returned "); + uart_hex(sd_rca>>32); + uart_hex(sd_rca); + uart_send('\n'); + if(sd_err) return sd_err; + + if((r=sd_clk(25000000))) return r; + + sd_cmd(CMD_CARD_SELECT,sd_rca); + if(sd_err) return sd_err; + + if(sd_status(SR_DAT_INHIBIT)) return SD_TIMEOUT; + *EMMC_BLKSIZECNT = (1<<16) | 8; + sd_cmd(CMD_SEND_SCR,0); + if(sd_err) return sd_err; + if(sd_int(INT_READ_RDY)) return SD_TIMEOUT; + + r=0; cnt=100000; while(r<2 && cnt) { + if( *EMMC_STATUS & SR_READ_AVAILABLE ) + sd_scr[r++] = *EMMC_DATA; + else + wait_msec(1); + } + if(r!=2) return SD_TIMEOUT; + if(sd_scr[0] & SCR_SD_BUS_WIDTH_4) { + sd_cmd(CMD_SET_BUS_WIDTH,sd_rca|2); + if(sd_err) return sd_err; + *EMMC_CONTROL0 |= C0_HCTL_DWITDH; + } + // add software flag + uart_puts("EMMC: supports "); + if(sd_scr[0] & SCR_SUPP_SET_BLKCNT) + uart_puts("SET_BLKCNT "); + if(ccs) + uart_puts("CCS "); + uart_send('\n'); + sd_scr[0]&=~SCR_SUPP_CCS; + sd_scr[0]|=ccs; + return SD_OK; +} diff --git a/0C_directory/sd.h b/0C_directory/sd.h new file mode 100644 index 00000000..5325a320 --- /dev/null +++ b/0C_directory/sd.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. + * + */ + +#define SD_OK 0 +#define SD_TIMEOUT -1 +#define SD_ERROR -2 + +int sd_init(); +int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num); diff --git a/0C_directory/start.S b/0C_directory/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/0C_directory/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/0C_directory/uart.c b/0C_directory/uart.c new file mode 100644 index 00000000..8297d9ff --- /dev/null +++ b/0C_directory/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 carachter 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/0C_directory/uart.h b/0C_directory/uart.h new file mode 100644 index 00000000..f74e5263 --- /dev/null +++ b/0C_directory/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/0D_readfile/Makefile b/0D_readfile/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/0D_readfile/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/0D_readfile/OLVASSEL.md b/0D_readfile/OLVASSEL.md new file mode 100644 index 00000000..00f854e0 --- /dev/null +++ b/0D_readfile/OLVASSEL.md @@ -0,0 +1,45 @@ +Oktatóanyag 0D - Fájl Beolvasása +================================ + +Megtanultuk, hogy kell beolvasni és értelmezni a gyökérkönyvtárat. Ebben az oktatóanyagban fogunk egy fájlt +a gyökérkönyvtárból, és a kluszterláncát végigjárva teljes egészében betöltjük a memóriába. + +```sh +$ qemu-system-aarch64 -M raspi3 -drive file=test.dd,if=sd,format=raw -serial stdio + ... kimenet törölve az átláthatóság miatt ... +FAT File LICENC~1BRO starts at cluster: 00000192 +FAT Bytes per Sector: 00000200 +FAT Sectors per Cluster: 00000004 +FAT Number of FAT: 00000002 +FAT Sectors per FAT: 00000014 +FAT Reserved Sectors Count: 00000004 +FAT First data sector: 00000054 + ... kimenet törölve az átláthatóság miatt ... +00085020: 43 6F 70 79 72 69 67 68 74 20 28 63 29 20 32 30 Copyright (c) 20 +00085030: 30 36 2C 20 42 72 6F 61 64 63 6F 6D 20 43 6F 72 06, Broadcom Cor +00085040: 70 6F 72 61 74 69 6F 6E 2E 0A 43 6F 70 79 72 69 poration..Copyri +00085050: 67 68 74 20 28 63 29 20 32 30 31 35 2C 20 52 61 ght (c) 2015, Ra +00085060: 73 70 62 65 72 72 79 20 50 69 20 28 54 72 61 64 spberry Pi (Trad +00085070: 69 6E 67 29 20 4C 74 64 0A 41 6C 6C 20 72 69 67 ing) Ltd.All rig + ... kimenet törölve az átláthatóság miatt ... +``` + +Fat.h, fat.c +------------ + +Ez is elég egyszerű és jól dokumentált. Megkeressük a fájlukhoz tartozó könyvtárbejegyzést, és kivesszük +belóle az induló kluszter számát. Ezután minden egyes klusztert betöltünk miközben végigjárjuk a láncot. + +`fat_getpartition()` betölti és értelmezi a partíció első szektorát. + +`fat_getcluster(fn)` visszaadja egy adott fájlnévhez tartozó kluszterlánc első tagját. + +`fat_readfile(clu)` rbeolvas egy fájlt a memóriába. Visszatérési értéke egy mutató a legelső beolvasott bájtra. + +Main +---- + +Miután inicializájuk az EMMC-t szektorok olvasásához, beolvassuk az első szektort a partícióról. Ha a BPB +egy érvényes FAT fájlrendszert ír le, akkor megkeressük a 'LICENCE.broadcom'-hoz tartozó első kluszter számát. +Ha ilyent nem találunk, akkor a 'kernel8.img'-t keresünk. Ha bármelyiket megtaláltuk, akkor betöltjük és +kidumpoljuk a fájl első 512 bájtját. diff --git a/0D_readfile/README.md b/0D_readfile/README.md new file mode 100644 index 00000000..35feab2e --- /dev/null +++ b/0D_readfile/README.md @@ -0,0 +1,44 @@ +Tutorial 0D - Read File +======================= + +We learned how to read and parse the root directory. In this tutorial we'll get one file from the +root directory, and walk through the cluster chain to load it entirely into memory. + +```sh +$ qemu-system-aarch64 -M raspi3 -drive file=test.dd,if=sd,format=raw -serial stdio + ... output removed for clearity ... +FAT File LICENC~1BRO starts at cluster: 00000192 +FAT Bytes per Sector: 00000200 +FAT Sectors per Cluster: 00000004 +FAT Number of FAT: 00000002 +FAT Sectors per FAT: 00000014 +FAT Reserved Sectors Count: 00000004 +FAT First data sector: 00000054 + ... output removed for clearity ... +00085020: 43 6F 70 79 72 69 67 68 74 20 28 63 29 20 32 30 Copyright (c) 20 +00085030: 30 36 2C 20 42 72 6F 61 64 63 6F 6D 20 43 6F 72 06, Broadcom Cor +00085040: 70 6F 72 61 74 69 6F 6E 2E 0A 43 6F 70 79 72 69 poration..Copyri +00085050: 67 68 74 20 28 63 29 20 32 30 31 35 2C 20 52 61 ght (c) 2015, Ra +00085060: 73 70 62 65 72 72 79 20 50 69 20 28 54 72 61 64 spberry Pi (Trad +00085070: 69 6E 67 29 20 4C 74 64 0A 41 6C 6C 20 72 69 67 ing) Ltd.All rig + ... output removed for clearity ... +``` + +Fat.h, fat.c +------------ + +This is also easy and pretty well documented. We locate the directory entry for our file, and get +the starting cluster number. Then we load each cluster into memory as we walk the cluster chain. + +`fat_getpartition()` load and check the boot record of the first MBR partition. + +`fat_getcluster(fn)` return the starting cluster for the given filename. + +`fat_readfile(clu)` reads a file into memory, returns pointer to the first byte. + +Main +---- + +Once we initialize EMMC to read sectors, we load the boot record of the first partition. If the BPB +describes a valid FAT partition, we find the starting cluster for the file 'LICENCE.broadcom'. If that +not found, we'll look for 'kernel8.img'. If any of these found, we load it and dump it's first 512 bytes. diff --git a/0D_readfile/delays.c b/0D_readfile/delays.c new file mode 100644 index 00000000..aba77264 --- /dev/null +++ b/0D_readfile/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(rfst[0]=='F' && bpb->fst[1]=='A' && bpb->fst[2]=='T') && + !(bpb->fst2[0]=='F' && bpb->fst2[1]=='A' && bpb->fst2[2]=='T')) { + uart_puts("ERROR: Unknown file system type\n"); + return 0; + } + return 1; + } + return 0; +} + +/** + * Find a file in root directory entries + */ +unsigned int fat_getcluster(char *fn) +{ + bpb_t *bpb=(bpb_t*)&_end; + fatdir_t *dir=(fatdir_t*)(&_end+512); + unsigned int root_sec, s; + // find the root directory's LBA + root_sec=((bpb->spf16?bpb->spf16:bpb->spf32)*bpb->nf)+bpb->rsc; + //WARNING gcc generates bad code for bpb->nr, causing unaligned exception + s=*((unsigned int*)&bpb->nf); + s>>=8; + s&=0xFFFF; + s<<=5; + // now s=bpb->nr*sizeof(fatdir_t)); + if(bpb->spf16==0) { + // adjust for FAT32 + root_sec+=(bpb->rc-2)*bpb->spc; + } + // add partition LBA + root_sec+=partitionlba; + // load the root directory + if(sd_readblock(root_sec,(unsigned char*)dir,s/512+1)) { + // iterate on each entry and check if it's the one we're looking for + for(;dir->name[0]!=0;dir++) { + // is it a valid entry? + if(dir->name[0]==0xE5 || dir->attr[0]==0xF) continue; + // filename match? + if(!__builtin_memcmp(dir->name,fn,11)) { + uart_puts("FAT File "); + uart_puts(fn); + uart_puts(" starts at cluster: "); + uart_hex(((unsigned int)dir->ch)<<16|dir->cl); + uart_puts("\n"); + // if so, return starting cluster + return ((unsigned int)dir->ch)<<16|dir->cl; + } + } + uart_puts("ERROR: file not found\n"); + } else { + uart_puts("ERROR: Unable to load root directory\n"); + } + return 0; +} + +/** + * Read a file into memory + */ +char *fat_readfile(unsigned int cluster) +{ + // BIOS Parameter Block + bpb_t *bpb=(bpb_t*)&_end; + // File allocation tables. We choose between FAT16 and FAT32 dynamically + unsigned int *fat32=(unsigned int*)(&_end+bpb->rsc*512); + unsigned short *fat16=(unsigned short*)fat32; + // Data pointers + unsigned int data_sec, s; + unsigned char *data, *ptr; + // find the LBA of the first data sector + data_sec=((bpb->spf16?bpb->spf16:bpb->spf32)*bpb->nf)+bpb->rsc; + //WARNING gcc generates bad code for bpb->nr, causing unaligned exception + s=*((unsigned int*)&bpb->nf); + s>>=8; + s&=0xFFFF; + s<<=5; + if(bpb->spf16>0) { + // adjust for FAT16 + data_sec+=(s+511)>>9; + } + // add partition LBA + data_sec+=partitionlba; + // dump important properties + uart_puts("FAT Bytes per Sector: "); + uart_hex(bpb->bps); + uart_puts("\nFAT Sectors per Cluster: "); + uart_hex(bpb->spc); + uart_puts("\nFAT Number of FAT: "); + uart_hex(bpb->nf); + uart_puts("\nFAT Sectors per FAT: "); + uart_hex((bpb->spf16?bpb->spf16:bpb->spf32)); + uart_puts("\nFAT Reserved Sectors Count: "); + uart_hex(bpb->rsc); + uart_puts("\nFAT First data sector: "); + uart_hex(data_sec); + uart_puts("\n"); + // load FAT table + s=sd_readblock(partitionlba+1,(unsigned char*)&_end+512,(bpb->spf16?bpb->spf16:bpb->spf32)+bpb->rsc); + // end of FAT in memory + data=ptr=&_end+512+s; + // iterate on cluster chain + while(cluster>1 && cluster<0xFFF8) { + // load all sectors in a cluster + sd_readblock((cluster-2)*bpb->spc+data_sec,ptr,bpb->spc); + // move pointer, sector per cluster * bytes per sector + ptr+=bpb->spc*bpb->bps; + // get the next cluster in chain + cluster=bpb->spf16>0?fat16[cluster]:fat32[cluster]; + } + return (char*)data; +} + diff --git a/0D_readfile/fat.h b/0D_readfile/fat.h new file mode 100644 index 00000000..31c3c8d4 --- /dev/null +++ b/0D_readfile/fat.h @@ -0,0 +1,28 @@ +/* + * 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. + * + */ + +int fat_getpartition(); +unsigned int fat_getcluster(char *fn); +char *fat_readfile(unsigned int cluster); diff --git a/0D_readfile/gpio.h b/0D_readfile/gpio.h new file mode 100644 index 00000000..52fa671d --- /dev/null +++ b/0D_readfile/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/0D_readfile/kernel8.img b/0D_readfile/kernel8.img new file mode 100755 index 00000000..5817812e Binary files /dev/null and b/0D_readfile/kernel8.img differ diff --git a/0D_readfile/link.ld b/0D_readfile/link.ld new file mode 100644 index 00000000..1352bfb1 --- /dev/null +++ b/0D_readfile/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/0D_readfile/main.c b/0D_readfile/main.c new file mode 100644 index 00000000..a5b19140 --- /dev/null +++ b/0D_readfile/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 "sd.h" +#include "fat.h" + +void main() +{ + unsigned int cluster; + // set up serial console + uart_init(); + + // initialize EMMC and detect SD card type + if(sd_init()==SD_OK) { + // read the master boot record and find our partition + if(fat_getpartition()) { + // find out file in root directory entries + cluster=fat_getcluster("LICENC~1BRO"); + if(cluster==0) + cluster=fat_getcluster("KERNEL8 IMG"); + if(cluster) { + // read into memory + uart_dump(fat_readfile(cluster)); + } + } else { + uart_puts("FAT partition not found???\n"); + } + } + + // echo everything back + while(1) { + uart_send(uart_getc()); + } +} diff --git a/0D_readfile/mbox.c b/0D_readfile/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/0D_readfile/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/0D_readfile/mbox.h b/0D_readfile/mbox.h new file mode 100644 index 00000000..8408d275 --- /dev/null +++ b/0D_readfile/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/0D_readfile/sd.c b/0D_readfile/sd.c new file mode 100644 index 00000000..3d9f8183 --- /dev/null +++ b/0D_readfile/sd.c @@ -0,0 +1,355 @@ +/* + * 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 "uart.h" +#include "delays.h" +#include "sd.h" + +#define EMMC_ARG2 ((volatile unsigned int*)(MMIO_BASE+0x00300000)) +#define EMMC_BLKSIZECNT ((volatile unsigned int*)(MMIO_BASE+0x00300004)) +#define EMMC_ARG1 ((volatile unsigned int*)(MMIO_BASE+0x00300008)) +#define EMMC_CMDTM ((volatile unsigned int*)(MMIO_BASE+0x0030000C)) +#define EMMC_RESP0 ((volatile unsigned int*)(MMIO_BASE+0x00300010)) +#define EMMC_RESP1 ((volatile unsigned int*)(MMIO_BASE+0x00300014)) +#define EMMC_RESP2 ((volatile unsigned int*)(MMIO_BASE+0x00300018)) +#define EMMC_RESP3 ((volatile unsigned int*)(MMIO_BASE+0x0030001C)) +#define EMMC_DATA ((volatile unsigned int*)(MMIO_BASE+0x00300020)) +#define EMMC_STATUS ((volatile unsigned int*)(MMIO_BASE+0x00300024)) +#define EMMC_CONTROL0 ((volatile unsigned int*)(MMIO_BASE+0x00300028)) +#define EMMC_CONTROL1 ((volatile unsigned int*)(MMIO_BASE+0x0030002C)) +#define EMMC_INTERRUPT ((volatile unsigned int*)(MMIO_BASE+0x00300030)) +#define EMMC_INT_MASK ((volatile unsigned int*)(MMIO_BASE+0x00300034)) +#define EMMC_INT_EN ((volatile unsigned int*)(MMIO_BASE+0x00300038)) +#define EMMC_CONTROL2 ((volatile unsigned int*)(MMIO_BASE+0x0030003C)) +#define EMMC_SLOTISR_VER ((volatile unsigned int*)(MMIO_BASE+0x003000FC)) + +// command flags +#define CMD_NEED_APP 0x80000000 +#define CMD_RSPNS_48 0x00020000 +#define CMD_ERRORS_MASK 0xfff9c004 +#define CMD_RCA_MASK 0xffff0000 + +// COMMANDs +#define CMD_GO_IDLE 0x00000000 +#define CMD_ALL_SEND_CID 0x02010000 +#define CMD_SEND_REL_ADDR 0x03020000 +#define CMD_CARD_SELECT 0x07030000 +#define CMD_SEND_IF_COND 0x08020000 +#define CMD_STOP_TRANS 0x0C030000 +#define CMD_READ_SINGLE 0x11220010 +#define CMD_READ_MULTI 0x12220032 +#define CMD_SET_BLOCKCNT 0x17020000 +#define CMD_APP_CMD 0x37000000 +#define CMD_SET_BUS_WIDTH (0x06020000|CMD_NEED_APP) +#define CMD_SEND_OP_COND (0x29020000|CMD_NEED_APP) +#define CMD_SEND_SCR (0x33220010|CMD_NEED_APP) + +// STATUS register settings +#define SR_READ_AVAILABLE 0x00000800 +#define SR_DAT_INHIBIT 0x00000002 +#define SR_CMD_INHIBIT 0x00000001 +#define SR_APP_CMD 0x00000020 + +// INTERRUPT register settings +#define INT_DATA_TIMEOUT 0x00100000 +#define INT_CMD_TIMEOUT 0x00010000 +#define INT_READ_RDY 0x00000020 +#define INT_CMD_DONE 0x00000001 + +#define INT_ERROR_MASK 0x017E8000 + +// CONTROL register settings +#define C0_SPI_MODE_EN 0x00100000 +#define C0_HCTL_HS_EN 0x00000004 +#define C0_HCTL_DWITDH 0x00000002 + +#define C1_SRST_DATA 0x04000000 +#define C1_SRST_CMD 0x02000000 +#define C1_SRST_HC 0x01000000 +#define C1_TOUNIT_DIS 0x000f0000 +#define C1_TOUNIT_MAX 0x000e0000 +#define C1_CLK_GENSEL 0x00000020 +#define C1_CLK_EN 0x00000004 +#define C1_CLK_STABLE 0x00000002 +#define C1_CLK_INTLEN 0x00000001 + +// SLOTISR_VER values +#define HOST_SPEC_NUM 0x00ff0000 +#define HOST_SPEC_NUM_SHIFT 16 +#define HOST_SPEC_V3 2 +#define HOST_SPEC_V2 1 +#define HOST_SPEC_V1 0 + +// SCR flags +#define SCR_SD_BUS_WIDTH_4 0x00000400 +#define SCR_SUPP_SET_BLKCNT 0x02000000 +// added by my driver +#define SCR_SUPP_CCS 0x00000001 + +#define ACMD41_VOLTAGE 0x00ff8000 +#define ACMD41_CMD_COMPLETE 0x80000000 +#define ACMD41_CMD_CCS 0x40000000 +#define ACMD41_ARG_HC 0x51ff8000 + +unsigned long sd_scr[2], sd_ocr, sd_rca, sd_err, sd_hv; + +/** + * Wait for data or command ready + */ +int sd_status(unsigned int mask) +{ + int cnt = 500000; while((*EMMC_STATUS & mask) && !(*EMMC_INTERRUPT & INT_ERROR_MASK) && cnt--) wait_msec(1); + return (cnt <= 0 || (*EMMC_INTERRUPT & INT_ERROR_MASK)) ? SD_ERROR : SD_OK; +} + +/** + * Wait for interrupt + */ +int sd_int(unsigned int mask) +{ + unsigned int r, m=mask | INT_ERROR_MASK; + int cnt = 1000000; while(!(*EMMC_INTERRUPT & m) && cnt--) wait_msec(1); + r=*EMMC_INTERRUPT; + if(cnt<=0 || (r & INT_CMD_TIMEOUT) || (r & INT_DATA_TIMEOUT) ) { *EMMC_INTERRUPT=r; return SD_TIMEOUT; } else + if(r & INT_ERROR_MASK) { *EMMC_INTERRUPT=r; return SD_ERROR; } + *EMMC_INTERRUPT=mask; + return 0; +} + +/** + * Send a command + */ +int sd_cmd(unsigned int code, unsigned int arg) +{ + int r=0; + sd_err=SD_OK; + if(code&CMD_NEED_APP) { + r=sd_cmd(CMD_APP_CMD|(sd_rca?CMD_RSPNS_48:0),sd_rca); + if(sd_rca && !r) { uart_puts("ERROR: failed to send SD APP command\n"); sd_err=SD_ERROR;return 0;} + code &= ~CMD_NEED_APP; + } + if(sd_status(SR_CMD_INHIBIT)) { uart_puts("ERROR: EMMC busy\n"); sd_err= SD_TIMEOUT;return 0;} + uart_puts("EMMC: Sending command ");uart_hex(code);uart_puts(" arg ");uart_hex(arg);uart_send('\n'); + *EMMC_INTERRUPT=*EMMC_INTERRUPT; *EMMC_ARG1=arg; *EMMC_CMDTM=code; + if(code==CMD_SEND_OP_COND) wait_msec(1000); else + if(code==CMD_SEND_IF_COND || code==CMD_APP_CMD) wait_msec(100); + if((r=sd_int(INT_CMD_DONE))) {uart_puts("ERROR: failed to send EMMC command\n");sd_err=r;return 0;} + r=*EMMC_RESP0; + if(code==CMD_GO_IDLE || code==CMD_APP_CMD) return 0; else + if(code==(CMD_APP_CMD|CMD_RSPNS_48)) return r&SR_APP_CMD; else + if(code==CMD_SEND_OP_COND) return r; else + if(code==CMD_SEND_IF_COND) return r==arg? SD_OK : SD_ERROR; else + if(code==CMD_ALL_SEND_CID) {r|=*EMMC_RESP3; r|=*EMMC_RESP2; r|=*EMMC_RESP1; return r; } else + if(code==CMD_SEND_REL_ADDR) { + sd_err=(((r&0x1fff))|((r&0x2000)<<6)|((r&0x4000)<<8)|((r&0x8000)<<8))&CMD_ERRORS_MASK; + return r&CMD_RCA_MASK; + } + return r&CMD_ERRORS_MASK; + // make gcc happy + return 0; +} + +/** + * read a block from sd card and return the number of bytes read + * returns 0 on error. + */ +int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num) +{ + int r,c=0,d; + if(num<1) num=1; + uart_puts("sd_readblock lba ");uart_hex(lba);uart_puts(" num ");uart_hex(num);uart_send('\n'); + if(sd_status(SR_DAT_INHIBIT)) {sd_err=SD_TIMEOUT; return 0;} + unsigned int *buf=(unsigned int *)buffer; + if(sd_scr[0] & SCR_SUPP_CCS) { + if(num > 1 && (sd_scr[0] & SCR_SUPP_SET_BLKCNT)) { + sd_cmd(CMD_SET_BLOCKCNT,num); + if(sd_err) return 0; + } + *EMMC_BLKSIZECNT = (num << 16) | 512; + sd_cmd(num == 1 ? CMD_READ_SINGLE : CMD_READ_MULTI,lba); + if(sd_err) return 0; + } else { + *EMMC_BLKSIZECNT = (1 << 16) | 512; + } + while( c < num ) { + if(!(sd_scr[0] & SCR_SUPP_CCS)) { + sd_cmd(CMD_READ_SINGLE,(lba+c)*512); + if(sd_err) return 0; + } + if((r=sd_int(INT_READ_RDY))){uart_puts("\rERROR: Timeout waiting for ready to read\n");sd_err=r;return 0;} + for(d=0;d<128;d++) buf[d] = *EMMC_DATA; + c++; buf+=128; + } + if( num > 1 && !(sd_scr[0] & SCR_SUPP_SET_BLKCNT) && (sd_scr[0] & SCR_SUPP_CCS)) sd_cmd(CMD_STOP_TRANS,0); + return sd_err!=SD_OK || c!=num? 0 : num*512; +} + +/** + * set SD clock to frequency in Hz + */ +int sd_clk(unsigned int f) +{ + unsigned int d,c=41666666/f,x,s=32,h=0; + int cnt = 100000; + while((*EMMC_STATUS & (SR_CMD_INHIBIT|SR_DAT_INHIBIT)) && cnt--) wait_msec(1); + if(cnt<=0) { + uart_puts("ERROR: timeout waiting for inhibit flag\n"); + return SD_ERROR; + } + + *EMMC_CONTROL1 &= ~C1_CLK_EN; wait_msec(10); + x=c-1; if(!x) s=0; else { + if(!(x & 0xffff0000u)) { x <<= 16; s -= 16; } + if(!(x & 0xff000000u)) { x <<= 8; s -= 8; } + if(!(x & 0xf0000000u)) { x <<= 4; s -= 4; } + if(!(x & 0xc0000000u)) { x <<= 2; s -= 2; } + if(!(x & 0x80000000u)) { x <<= 1; s -= 1; } + if(s>0) s--; + if(s>7) s=7; + } + if(sd_hv>HOST_SPEC_V2) d=c; else d=(1<HOST_SPEC_V2) h=(d&0x300)>>2; + d=(((d&0x0ff)<<8)|h); + *EMMC_CONTROL1=(*EMMC_CONTROL1&0xffff003f)|d; wait_msec(10); + *EMMC_CONTROL1 |= C1_CLK_EN; wait_msec(10); + cnt=10000; while(!(*EMMC_CONTROL1 & C1_CLK_STABLE) && cnt--) wait_msec(10); + if(cnt<=0) { + uart_puts("ERROR: failed to get stable clock\n"); + return SD_ERROR; + } + return SD_OK; +} + +/** + * initialize EMMC to read SDHC card + */ +int sd_init() +{ + long r,cnt,ccs=0; + // GPIO_CD + r=*GPFSEL4; r&=~(7<<(7*3)); *GPFSEL4=r; + *GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<15); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; + r=*GPHEN1; r|=1<<15; *GPHEN1=r; + + // GPIO_CLK, GPIO_CMD + r=*GPFSEL4; r|=(7<<(8*3))|(7<<(9*3)); *GPFSEL4=r; + *GPPUD=2; wait_cycles(150); *GPPUDCLK1=(1<<16)|(1<<17); wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; + + // GPIO_DAT0, GPIO_DAT1, GPIO_DAT2, GPIO_DAT3 + r=*GPFSEL5; r|=(7<<(0*3)) | (7<<(1*3)) | (7<<(2*3)) | (7<<(3*3)); *GPFSEL5=r; + *GPPUD=2; wait_cycles(150); + *GPPUDCLK1=(1<<18) | (1<<19) | (1<<20) | (1<<21); + wait_cycles(150); *GPPUD=0; *GPPUDCLK1=0; + + sd_hv = (*EMMC_SLOTISR_VER & HOST_SPEC_NUM) >> HOST_SPEC_NUM_SHIFT; + uart_puts("EMMC: GPIO set up\n"); + // Reset the card. + *EMMC_CONTROL0 = 0; *EMMC_CONTROL1 |= C1_SRST_HC; + cnt=10000; do{wait_msec(10);} while( (*EMMC_CONTROL1 & C1_SRST_HC) && cnt-- ); + if(cnt<=0) { + uart_puts("ERROR: failed to reset EMMC\n"); + return SD_ERROR; + } + uart_puts("EMMC: reset OK\n"); + *EMMC_CONTROL1 |= C1_CLK_INTLEN | C1_TOUNIT_MAX; + wait_msec(10); + // Set clock to setup frequency. + if((r=sd_clk(400000))) return r; + *EMMC_INT_EN = 0xffffffff; + *EMMC_INT_MASK = 0xffffffff; + sd_scr[0]=sd_scr[1]=sd_rca=sd_err=0; + sd_cmd(CMD_GO_IDLE,0); + if(sd_err) return sd_err; + + sd_cmd(CMD_SEND_IF_COND,0x000001AA); + if(sd_err) return sd_err; + cnt=6; r=0; while(!(r&ACMD41_CMD_COMPLETE) && cnt--) { + wait_cycles(400); + r=sd_cmd(CMD_SEND_OP_COND,ACMD41_ARG_HC); + uart_puts("EMMC: CMD_SEND_OP_COND returned "); + if(r&ACMD41_CMD_COMPLETE) + uart_puts("COMPLETE "); + if(r&ACMD41_VOLTAGE) + uart_puts("VOLTAGE "); + if(r&ACMD41_CMD_CCS) + uart_puts("CCS "); + uart_hex(r>>32); + uart_hex(r); + uart_send('\n'); + if(sd_err!=SD_TIMEOUT && sd_err!=SD_OK ) { + uart_puts("ERROR: EMMC ACMD41 returned error\n"); + return sd_err; + } + } + if(!(r&ACMD41_CMD_COMPLETE) || !cnt ) return SD_TIMEOUT; + if(!(r&ACMD41_VOLTAGE)) return SD_ERROR; + if(r&ACMD41_CMD_CCS) ccs=SCR_SUPP_CCS; + + sd_cmd(CMD_ALL_SEND_CID,0); + + sd_rca = sd_cmd(CMD_SEND_REL_ADDR,0); + uart_puts("EMMC: CMD_SEND_REL_ADDR returned "); + uart_hex(sd_rca>>32); + uart_hex(sd_rca); + uart_send('\n'); + if(sd_err) return sd_err; + + if((r=sd_clk(25000000))) return r; + + sd_cmd(CMD_CARD_SELECT,sd_rca); + if(sd_err) return sd_err; + + if(sd_status(SR_DAT_INHIBIT)) return SD_TIMEOUT; + *EMMC_BLKSIZECNT = (1<<16) | 8; + sd_cmd(CMD_SEND_SCR,0); + if(sd_err) return sd_err; + if(sd_int(INT_READ_RDY)) return SD_TIMEOUT; + + r=0; cnt=100000; while(r<2 && cnt) { + if( *EMMC_STATUS & SR_READ_AVAILABLE ) + sd_scr[r++] = *EMMC_DATA; + else + wait_msec(1); + } + if(r!=2) return SD_TIMEOUT; + if(sd_scr[0] & SCR_SD_BUS_WIDTH_4) { + sd_cmd(CMD_SET_BUS_WIDTH,sd_rca|2); + if(sd_err) return sd_err; + *EMMC_CONTROL0 |= C0_HCTL_DWITDH; + } + // add software flag + uart_puts("EMMC: supports "); + if(sd_scr[0] & SCR_SUPP_SET_BLKCNT) + uart_puts("SET_BLKCNT "); + if(ccs) + uart_puts("CCS "); + uart_send('\n'); + sd_scr[0]&=~SCR_SUPP_CCS; + sd_scr[0]|=ccs; + return SD_OK; +} diff --git a/0D_readfile/sd.h b/0D_readfile/sd.h new file mode 100644 index 00000000..5325a320 --- /dev/null +++ b/0D_readfile/sd.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. + * + */ + +#define SD_OK 0 +#define SD_TIMEOUT -1 +#define SD_ERROR -2 + +int sd_init(); +int sd_readblock(unsigned int lba, unsigned char *buffer, unsigned int num); diff --git a/0D_readfile/start.S b/0D_readfile/start.S new file mode 100644 index 00000000..27d0c503 --- /dev/null +++ b/0D_readfile/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/0D_readfile/uart.c b/0D_readfile/uart.c new file mode 100644 index 00000000..8297d9ff --- /dev/null +++ b/0D_readfile/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 carachter 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/0D_readfile/uart.h b/0D_readfile/uart.h new file mode 100644 index 00000000..f74e5263 --- /dev/null +++ b/0D_readfile/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/LICENSE b/LICENSE new file mode 100644 index 00000000..152cfc7f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ + Copyright (C) 2017 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. diff --git a/OLVASSEL.md b/OLVASSEL.md new file mode 100644 index 00000000..596177da --- /dev/null +++ b/OLVASSEL.md @@ -0,0 +1,133 @@ +A Raspberry Pi 3 alacsony szintű programozása +============================================= + +Üdvözöllek! Ez az oktatóanyag azok számára készült, akik szeretnének saját alacsony szintű (bare metal) +programot írni a Raspberry Pi-jükre. + +A célközönsége elsősorban azok a hobby OS fejlesztők, akik most ismerkednek ezzel a hardverrel. Példákat mutatok +arra, hogyan kell az alapfunkciókat megvalósítani, úgy mint soros vonalra írás, billentyűleütés kiolvasás, beállítani +a képernyő felbontását és rajzolni rá. Azt is megmutatom, hogy kell az alaplap sorszámát és igazi, vas által +generált véletlenszámot kiolvasni, valamint hogy hogyan kell fájlokat beolvasni a kártyáról. + +Ez az oktatóanyag *nem* arról szól, hogy hogyan írjunk operációs rendszert. Nem érint olyan témákat, mint a +memória gazdálkodás, virtuális fájlrendszer kezelés, vagy hogy hogyan valósítsuk meg a multitaszkot. Ha saját +OS-t szeretnél írni a Raspberry Pi-re, akkor javaslom előbb nézz körbe máshol, mielőtt folytatnád. Ez az +oktatóanyag kifejezetten arról szól, hogy kommunikáljunk az adott hardverrel, és nem az operációs rendszerek +hátteréről. + +Feltételezem, hogy elegendő GNU/Linux ismerettel rendelkezel, tudod, hogy kell programokat fordítani és lemez +valamint fájlrendszer képfájlokat létrehozni. Nem fogok kitérni ezekre, bár szó lesz arról, hogyan állítsuk be +a kereszt-fordítót kifejezetten ehhez az architektúrához. + +Miért Raspberry Pi 3? +--------------------- + +Több okból is erre esett a választásom: először is olcsó, könnyen beszerezhető. Másodszor teljesen 64 bites +masina. Már réges rég felhagytam a 32 bites fejlesztéssel, mivel a 64 bit sokkal izgalmasabb. A címterülete +hatalmas, nagyobb, mint a tárolókapacitás, ezért lehetővé teszi új, izgalmas megoldások létrehozását. +Harmadsorban MMIO-t használ, amit könnyű programozni. + +Előkészületek +------------- + +Mielőtt belevágnánk, szükséged lesz egy kereszt-fordítóra (lásd 00_crosscompiler könyvtár) és egy Micro SD +kártyára néhány [firmware fájllal](https://github.com/raspberrypi/firmware/tree/master/boot) egy FAT partíción. + +Javaslom, hogy szerezz be egy [Micro SD kártya USB adaptert](http://media.kingston.com/images/products/prodReader-FCR-MRG2-img.jpg) +(sok gyártó eleve szállít ilyent az SD kártyáihoz), hogy könnyedén csatlakoztathasd az asztali gépedhez, mint egy +pent, speciális kártya olvasó interfész nélkül (habár sok laptopban gyárilag van ilyen olvasó manapság). + +Az MBR partíciós táblát létre kell hozni az SD kártyán LBA FAT32 (0x0C típusú) partícióval, leformázni azt, +majd rámásolni a bootcode.bin és start.elf állományokat. Alternatívaként letöltheted a raspbian képfájlt, `dd`-vel +rárakhatod a kártyára, majd mountolás után letörölheted a felesleges .img fájlokat. Amenyik szimpatikusabb. A lényeg +az, hogy ezekben az oktatóanyagokban `kernel8.img` fájlokat gyártunk, amit a partíció gyökér könyvtárába kell másolni, +és más `.img` kiterjesztésű fájl nem lehet ott. + +Javaslom továbbá, hogy vegyél egy [soros USB debug kábelt](https://www.adafruit.com/product/954). Ezt a GPIO 14-es +és 15-ös lábára kell csatlakoztatni, az asztali gépen pedig a következő paranccsal kell elindítani a minicom-ot: + +```sh +minicom -b 115200 -D /dev/ttyUSB0 +``` + +Emulálás +-------- + +Sajnálatos módon a hivatalos qemu nem támogatja a Raspberry Pi 3-at, csak a 2-t. De van egy jó hírem, megírtam +a támogatást hozzá, és a forrást elérhetővé tettem a [github](https://github.com/bztsrc/qemu-raspi3)-on. Miután +lefordult, így tudod használni: + +```sh +qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial stdio +``` + +Vagy (a fájl rendszer oktatóanyagok esetében) + +```sh +qemu-system-aarch64 -M raspi3 -drive file=$(yourimagefile),if=sd,format=raw -serial stdio +``` + +Az első paraméter utasítja a qemu-t a Raspberry Pi 3 hardver emulálására. A második megadja a használandó kernel +fájl (vagy a második esetben az SD kártya képfájl) nevét. Végezetül az utolsó paraméter lehetővé teszi, hogy az +emulált gép UART0-ját átirányítsuk a qemu-t futtató terminál be- és kimenetére, azaz hogy minden, a virtuális gépen +soros vonalra küldött karater megjelenjen a terminálon, az ott leütött karaktereket pedig kiolvashassuk a vm-en. Ez +csak az 5-ös oktatóanyagtól működik, mivel az UART1 alapból *nem* átirányítható. + +**!!!FIGYELEM!!!** Qemu emulálása felületes, csak a legáltalánosabb perifériákat támogatja! **!!!FIGYELEM!!!** + +Magáról a hardverről +-------------------- + +Rengeteg oldal foglalkozik az interneten a Raspberry Pi 3 hardverének részletes bemutatásával, szóval itt rövid +leszek, és csak az alapokat futjuk át. + +Az alaplapon egy [BCM2837 SoC](https://github.com/raspberrypi/documentation/tree/master/hardware/raspberrypi/bcm2837) csip +található. Ebbe beszereltek + + - VideoCore grafikus processzort (GPU) + - ARM-Cortex-A7 általános processzort (CPU, ARMv8) + - És néhány MMIO-val leképzett perifériát. + +Érdekesség, hogy a nem a CPU a fő processzor. Amikor bekapcsoljuk, először a GPU kezd futni. Amikor végzett az +inicializálásával, ami a bootcode.bin futtatását jelenti, betölti a start.elf programot. Ez nem egy ARM-es futtatható +állomány, hanem a GPU-ra íródott. Ami számunkra érdekes, az az, hogy ez a start.elf különféle ARM futtathatók után +kutat, melyek mind `kernel`-el kezdődnek, és `.img`-re végződnek. Mivel mi a CPU-t AArch64 módban fogjuk programozni, +ezért nekünk a `kernel8.img` fájlra van szükségünk, ami a legutolsó keresett fájlnév. Miután betöltötte, a GPU magasba +emeli az ARM processzor reset lábát, aminek hatására elkezdi a futtatást a 0x80000-as címen (egész pontosan a 0-ás +címen, csak oda a GPU egy ARM ugrás utasítás rakott előtte). + +A RAM (1G a Raspberry Pi 3-on) meg van osztva a CPU és a GPU között, ezért az egyik tudja olvasni, amit a másik +a memóriába írt. A félreértések elkerülése végett egy jól definiált, úgy nevezett levelesláda [mailbox](https://github.com/raspberrypi/firmware/wiki/Mailboxes) +interfészt alakítottak ki. A CPU beletesz egy üzenetet a levesládába, és szól a GPU-nak, hogy üzenete van. A GPU +(tudván, hogy a teljes üzenet a memóriában van) értelmezi azt, és ugyanarra a címre egy választ rak. A CPU-nak +folyamatosan figyelni kell a memóriát, hogy végzett-e a GPU, és ha igen, akkor és csak akkor kiolvashatja a választ. + +Hasonlóan a perifáriák is a memórián keresztül kommunikálnak a CPU-val. Mindegyiknek saját dedikált címe van, +0x3F000000-tól kezdődően, de ez nem igazi RAM (MMIO, memóriába leképzett ki- és bemenet). Namost itt nincs levelesláda, +minden eszköz saját protokollt beszél. Ami közös, az az, hogy ez a memóriarész csak 32 bites adagokban, 4-el osztható +címen írható / olvasható (szavak), és mindegyiknek kontroll/státusz illetve adat szavai vannak. Sajnálatos módon +a Broadcom (a SoC gyártója) hírhedten szarul dokumentája a termékeit. A legjobb, ami van, a BCM2835-ös leírása, ami +azért eléggé hasonló. + +Van továbbá lapcímfordító egység (MMU) a CPU-ban ami lehetővé teszi virtuális címterek használatát. Ez néhány +speciális CPU rendszer regiszterrel programozható, és oda kell figyelni, amikor ezeket az MMIO területeket képezük le +vele a virtuális címtérbe. + +Néhány az érdekesebb MMIO címek közül: +``` +0x3F003000 - Rendszer Időzítő (System Timer) +0x3F00B000 - Megszakítás vezérlő (Interrupt controller) +0x3F00B880 - VideoCore levelesláda (VideoCore mailbox) +0x3F100000 - Energiagazdálkodás (Power management) +0x3F104000 - Véletlenszám generátor (Random Number Generator) +0x3F200000 - Általános célú ki- és bemenet vezérlő (General Purpose IO controller) +0x3F201000 - UART0 (soros port, PL011) +0x3F215000 - UART1 (soros port, AUX mini UART) +0x3F300000 - Külső tároló vezérlő (External Mass Media Controller, SD kártya olvasás) +0x3F980000 - USB vezérlő (Universal Serial Bus controller) +``` +A többi információ megtalálható a Raspberry Pi firmware wiki-ben és a documentation repóban a github-on. +https://github.com/raspberrypi + +Sok szerencsét és élvezetes hekkelést a Raspberry-dhez! :-) +bzt diff --git a/README.md b/README.md new file mode 100644 index 00000000..aa089ebe --- /dev/null +++ b/README.md @@ -0,0 +1,127 @@ +Bare Metal Programming on Raspberry Pi 3 +======================================== + +Hello there! This tutotial series are made for those who would like to compile their own bare metal application +for the Raspberry Pi. + +The target audience is hobby OS developers, who are new to this hardware. I'll give you examples on how to do the +basic things, like writing to the serial console, reading keystrokes from it, setting screen resolution and draw to +the linear frame buffer. I'm also going to show you how to get the hardware's serial number, a hardware-backed random +number, and how to read files from the boot partition. + +This is *not* a tutorial on how to write an OS. I won't cover topics like memory management and virtual file systems, +or how to implement multi-tasking. If you plan to write your own OS for the Raspberry Pi, I suggest to do some +research before you continue. This tutorial is strickly about interfacing with the hardware, and not about OS theory. + +I assume you have a fair GNU/Linux knowledge on how to compile programs and create disk and file system images. I +won't cover those in detail, although I'll talk about how to set up a cross-compiler for this architecture. + +Why Raspberry Pi 3? +------------------- + +I've choosen this board for several reasons: first of all, it's cheap and easy to get. Second, it's a 64 bit +machine. I gave up programming for 32 bit long long time ago. The 64 bit is so much more interesting, as it's +address space is increadibly huge, bigger than the storage capacity which allows us to use some interesting new +solutions. Third, uses only MMIO which makes it easy to program. + +Prerequirements +--------------- + +Before you can start, you'll need a cross-compiler (see 00_crosscompiler directory for details) +and a Micro SD card with [firmware files](https://github.com/raspberrypi/firmware/tree/master/boot) on a FAT filesystem. + +I recommend to get a [Micro SD card USB adapter](http://media.kingston.com/images/products/prodReader-FCR-MRG2-img.jpg) +(many manufacturers ship SD cards with such an adapter), so that you can connect the card to any desktop computer just +like an USB stick, no special card reader interface required (although many laptops have those these days). + +You can create an MBR partitioning scheme on the SD card with an LBA FAT32 (type 0x0C) partition, format it +and copy bootcode.bin and start.elf onto it. Or alternatively you can download a raspbian image, `dd` it to the SD card, +mount it and delete the unnecessary .img files. Whichever you prefer. What's important, you'll create `kernel8.img` +with these tutorials which must be copied to the root directory on the SD card, and no other `.img` files should exists +there. + +I'd also recommend to get an [USB serial debug cable](https://www.adafruit.com/product/954). You connect it to the +GPIO pins 14/15, and run minicom on your desktop computer like + +```sh +minicom -b 115200 -D /dev/ttyUSB0 +``` + +Emulation +--------- + +Unfortunately official qemu does not support Raspberry Pi 3, only Raspberry Pi 2. But good news, I've implemented +that, and made the source available on [github](https://github.com/bztsrc/qemu-raspi3). Once compiled, you can use it with: + +```sh +qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial stdio +``` + +Or (with the file system tutorials) + +```sh +qemu-system-aarch64 -M raspi3 -drive file=$(yourimagefile),if=sd,format=raw -serial stdio +``` + +The first argument tells qemu to emulate Raspberry Pi 3 hardware. The second tells the kernel filename (or in second +case the SD card image) to be used. Finally the last argument redirects the emulated UART0 to the standard input/output +of the terminal running qemu, so that everything sent to the serial line will be displayed, and every key typed in the +terminal will be received by the vm. Only works with the tutorials 05 and above, as UART1 is *not* redirected by default. + +**!!!WARNING!!!** Qemu emulation is rudimentary, only the most common peripherals are emulated! **!!!WARNING!!!** + +About the hardware +------------------ + +There are lots of pages on the internet describing the Raspberry Pi 3 hardware in detail, so I'll be brief and +cover only the basics. + +The board is shipped with a [BCM2837 SoC](https://github.com/raspberrypi/documentation/tree/master/hardware/raspberrypi/bcm2837) chip. +That includes a + + - VideoCore GPU + - ARM-Cortex-A7 CPU (ARMv8) + - Some MMIO mapped pheripherals. + +Interestingly the CPU is not the main processor on the board. When it's powered up, first GPU runs. When it's +finished with the initialization by executing the code in bootcode.bin, it will load and execute the start.elf executable. +That's not an ARM executable, but compiled for the GPU. What interests us is that start.elf looks for different +ARM executables, all starting with `kernel` and ending in `.img`. As we're going to program the CPU in AArch64 mode, +we'll need `kernel8.img` only, which is the last to look for. Once it's loaded, the GPU triggers the reset line on +the ARM processor, which starts executing code at address 0x80000 (or more precisely at 0, but the GPU puts an ARM +jump code there first). + +The RAM (1G for the Raspberry Pi 3) is shared among the CPU and the GPU, meaning one can read what the other has +written into memory. To avoid confusion, a well defined, so called [mailbox interface](https://github.com/raspberrypi/firmware/wiki/Mailboxes) +is established. The CPU writes a message into the mailbox, and tells the GPU to read it. The GPU (knowing that the +message is entirely in memory) interprets it, and places a response message at the same address. The CPU has +to poll the memory to know when the GPU is finished, and then it can read the response. + +Similarily, all peripherals communicates in memory with the CPU. Each has it's dedicated memory address starting from +0x3F000000, but it's not in real RAM (called Memory Mapped IO). Now there's no mailbox for peripherals, instead each +device has it's own protocol. What's common for these devices that their memory must be read and written in 32 bit +units at 4 bytes aligned addresses (so called words), and each has control/status and data words. Unfortunately +Broadcom (the manucafturer of the SoC chip) is legendary bad at documenting their products. The best we've got is the +BCM2835 documentation, which is close enough. + +There's also a Memory Management Unit in the CPU which allows creating virtual address spaces. This can be programmed +by specific CPU registers, and care must be taken when you map these MMIO addresses into a virtual address space. + +Some of the more interesting MMIO addresses are: +``` +0x3F003000 - System Timer +0x3F00B000 - Interrupt controller +0x3F00B880 - VideoCore mailbox +0x3F100000 - Power management +0x3F104000 - Random Number Generator +0x3F200000 - General Purpose IO controller +0x3F201000 - UART0 (serial port, PL011) +0x3F215000 - UART1 (serial port, AUX mini UART) +0x3F300000 - External Mass Media Controller (SD card reader) +0x3F980000 - Universal Serial Bus controller +``` +For more information, see Raspberry Pi firmware wiki and documentation on github. +https://github.com/raspberrypi + +Good luck and enjoy hacking with your Raspberry! :-) +bzt