From 2fc348ba46d2cdeaf21113dd1542c11dc93d37c1 Mon Sep 17 00:00:00 2001 From: bzt Date: Sat, 13 Jan 2018 13:39:38 +0100 Subject: [PATCH] Fixed typos and more tutorials --- 0E_initrd/OLVASSEL.md | 4 +- 0F_executionlevel/OLVASSEL.md | 4 +- 10_virtualmemory/OLVASSEL.md | 4 +- 11_exceptions/Makefile | 43 +++++++++ 11_exceptions/OLVASSEL.md | 46 +++++++++ 11_exceptions/README.md | 45 +++++++++ 11_exceptions/exc.c | 88 +++++++++++++++++ 11_exceptions/gpio.h | 45 +++++++++ 11_exceptions/kernel8.img | Bin 0 -> 8248 bytes 11_exceptions/link.ld | 46 +++++++++ 11_exceptions/main.c | 48 +++++++++ 11_exceptions/mbox.c | 63 ++++++++++++ 11_exceptions/mbox.h | 47 +++++++++ 11_exceptions/mmu.c | 177 ++++++++++++++++++++++++++++++++++ 11_exceptions/mmu.h | 26 +++++ 11_exceptions/start.S | 123 +++++++++++++++++++++++ 11_exceptions/uart.c | 126 ++++++++++++++++++++++++ 11_exceptions/uart.h | 30 ++++++ 18 files changed, 959 insertions(+), 6 deletions(-) create mode 100644 11_exceptions/Makefile create mode 100644 11_exceptions/OLVASSEL.md create mode 100644 11_exceptions/README.md create mode 100644 11_exceptions/exc.c create mode 100644 11_exceptions/gpio.h create mode 100755 11_exceptions/kernel8.img create mode 100644 11_exceptions/link.ld create mode 100644 11_exceptions/main.c create mode 100644 11_exceptions/mbox.c create mode 100644 11_exceptions/mbox.h create mode 100644 11_exceptions/mmu.c create mode 100644 11_exceptions/mmu.h create mode 100644 11_exceptions/start.S create mode 100644 11_exceptions/uart.c create mode 100644 11_exceptions/uart.h diff --git a/0E_initrd/OLVASSEL.md b/0E_initrd/OLVASSEL.md index 54de8764..e9bcbd5c 100644 --- a/0E_initrd/OLVASSEL.md +++ b/0E_initrd/OLVASSEL.md @@ -1,5 +1,5 @@ -Tutorial 0E - Kezdeti memória lemez -=================================== +Oktatóanyag 0E - Kezdeti memória lemez +====================================== Sok OS használ kezdeti memória lemezt (initrd) hogy fájlokat töltsön be induláskor. Szükségét éreztem egy ilyen oktatóanyagnak, mivel a legtöbb hobby OS fejlesztőnek fingja sincs, hogy kell ezt rendesen csinálni. diff --git a/0F_executionlevel/OLVASSEL.md b/0F_executionlevel/OLVASSEL.md index e7b830e7..7c52162e 100644 --- a/0F_executionlevel/OLVASSEL.md +++ b/0F_executionlevel/OLVASSEL.md @@ -1,5 +1,5 @@ -Tutorial 0F - Futási szintek -============================ +Oktatóanyag 0F - Futási szintek +=============================== Mielőtt rátérhetnénk a virtuális memóriára, beszélnünk kell a futási szintekről. Minden szintnek saját lapfordító tára van, emiatt életbevágó, hogy tudjuk, melyik szinten futunk éppen. Ezért ebben az oktatóanyagban diff --git a/10_virtualmemory/OLVASSEL.md b/10_virtualmemory/OLVASSEL.md index edcd12e2..2c97dbfc 100644 --- a/10_virtualmemory/OLVASSEL.md +++ b/10_virtualmemory/OLVASSEL.md @@ -1,5 +1,5 @@ -Tutorial 10 - Virtuális Memória -=============================== +Oktatóanyag 10 - Virtuális Memória +================================== Elérkeztünk a legegyszerűbb és egyben legbonyolultabb oktatóanyagunkhoz. Egyszerű, mert nem csinálunk mást, mint feltöltünk egy tömböt, aztán beállítunk pár regisztert. A nehézség abban rejlik, hogy mi kerüljön a tömbbe. diff --git a/11_exceptions/Makefile b/11_exceptions/Makefile new file mode 100644 index 00000000..f6ba7559 --- /dev/null +++ b/11_exceptions/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/11_exceptions/OLVASSEL.md b/11_exceptions/OLVASSEL.md new file mode 100644 index 00000000..64c189b7 --- /dev/null +++ b/11_exceptions/OLVASSEL.md @@ -0,0 +1,46 @@ +Oktatóanyag 11 - Kivételkezelők +=============================== + +Legutóbb egy nagyon egyszerű címfordítási táblát használtunk, de a mindennapi életben többre van szükség. +Nem könnyű vakon létrehozni ezt a táblát, ezért kivételkezelőket fogunk definiálni. Ez ki fogja dumpolni +a fontos rendszer regisztereket, hogy azonosíthassuk és megtalálhassuk a problémát a címfordítási táblánkban. + +```sh +$ qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial stdio +Synchronous: Data abort, same EL, Translation fault at level 2: + ESR_EL1 0000000096000006 ELR_EL1 0000000000080D7C + SPSR_EL1 00000000200003C4 FAR_EL1 FFFFFFFFFF000000 +``` + +Az ESR_EL1 elárulja, hogy Adathozzáférési probléma (Data Abort) lépett fel a táblázat második szintjén. Az +utasítás, ami okozta, a 0x80D7C címen található, és a 0xFFFFFFFFFF000000 címet szerette volna elérni. + +A megadott vektor hasonló az AMD64 IDT-jéhez, két eltéréssel: először is, nincs külön utasítás (mint az sidt), +hanem egy rendszer regiszter tárolja a címét. Másodszor, nem egy címeket tartalmazó táblázat címét adjuk meg, +hanem a konkrét kód címét. Ezért minden "bejegyzés" a táblában nagyobb, kis programrészek amikkel be lehet +állítani a paramétereket és meghívni egy közös kivételkezelőt. + +AMD64-en 32 belépési pont van, minden egyes kivételtípushoz egy. AArch-on ezzel szemben csak egy van, és egy +rendszer regiszterből olvasható ki, melyik kivételtípusról van szó. Figyelembe véve, hogy minden OS úgyis csak +átad egy kivételkódot egy közös kivételkezelőnek, ezzel megkönnyíti az életünket. + +Exc.c +----- + +`exc_handler()` egy egyszerű kivételkezelő, ami kidumpolja a regisztereket és dekódolja az ESR_EL1-t (részben). +Aztán megállítjuk a CPU-t, mert egyelőre nincs hova visszatérni a kivételkezelőből. A Kivétel Szindróma Regiszter +(Exception Syndrome Register) részletes leírása megtalálható az ARM DDI0487B_b könyv D10.2.28 fejezetében. + +Start +----- + +Mielőtt rendszerfelügyeleti módra váltanánk, beállítjuk a *vbar_el2*-t. Fontos, hogy az EL1 szinten fellépő +kivételeket EL2 szinten futó kód kezeli le. Minden kezelőt megfelelően kell pozicionálni a memóriában. Qemu +nem érzékeny annyira erre, de az igazi vas igen. + +`_vectors` kivételkezelők vektor táblája, kis assembly programokkal, mind az `exc_handler()` nevű C függvényt hívja. + +Main +---- + +Beállítjuk a címfordítást, majd szándékosan egy leképezetlen címre hivatkozunk, hogy kivételt idézzünk elő. diff --git a/11_exceptions/README.md b/11_exceptions/README.md new file mode 100644 index 00000000..ac21bf11 --- /dev/null +++ b/11_exceptions/README.md @@ -0,0 +1,45 @@ +Tutorial 11 - Exceptions +======================== + +Last time we have used a very simple translation scheme, but in real life you often need more. And it is not +easy to write the table blindly, so we're going to add exception handlers this time. This will print out some +system registers to identify the problem with our translation tables. + +```sh +$ qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial stdio +Synchronous: Data abort, same EL, Translation fault at level 2: + ESR_EL1 0000000096000006 ELR_EL1 0000000000080D7C + SPSR_EL1 00000000200003C4 FAR_EL1 FFFFFFFFFF000000 +``` + +Here ESR_EL1 tells us that it was a Data Abort, caused by a translation table error at level 2. The instruction +triggered it is at address 0x80D7C which tried to access memory at 0xFFFFFFFFFF000000. + +The vector is very similar to AMD64's IDT, with two exceptions: first, there's no special instruction (like sidt), +but a system register stores the address. Second, we don't pass a table with addresses rather the address of the +actual code. Therefore each "entry" of the vector table is bigger, small stubs so that you can set up arguments +and jump to a common handler. + +On AMD64 you have 32 entry points for each exception. On AArch, you only have one, and you can read the excpetion +code from a system register. Considering that all OS sets a code for the exception and jumps to a common handler, +this makes life easier. + +Exc.c +----- + +`exc_handler()` a simple exception handler that dumps registers and decodes ESR_EL1 (partially). We simply stop +the CPU for now, as we have no means to recover from an exception yet. The full comprehensive description of +Exception Syndrome Register can be found in ARM DDI0487B_b chapter D10.2.28. + +Start +----- + +Before we switch to supervisor mode, we set up *vbar_el2*. Note that exceptions triggered at EL1 will be handled +by code at EL2. All handlers must be properly aligned. Qemu is not so picky, but real hardware is. + +`_vectors` the exception handler's vector table with small assembly stubs, each calling `exc_handler()` in C. + +Main +---- + +We set up page translations, and then we deliberatly reference an unmapped address to trigger an exception. diff --git a/11_exceptions/exc.c b/11_exceptions/exc.c new file mode 100644 index 00000000..8ca925de --- /dev/null +++ b/11_exceptions/exc.c @@ -0,0 +1,88 @@ +/* + * 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" + +/** + * common exception handler + */ +void exc_handler(unsigned long type, unsigned long esr, unsigned long elr, unsigned long spsr, unsigned long far) +{ + // print out interruption type + switch(type) { + case 0: uart_puts("Synchronous"); break; + case 1: uart_puts("IRQ"); break; + case 2: uart_puts("FIQ"); break; + case 3: uart_puts("SError"); break; + } + uart_puts(": "); + // decode exception type (some, not all. See ARM DDI0487B_b chapter D10.2.28) + switch(esr>>26) { + case 0b000000: uart_puts("Unknown"); break; + case 0b000001: uart_puts("Trapped WFI/WFE"); break; + case 0b001110: uart_puts("Illegal execution"); break; + case 0b010101: uart_puts("System call"); break; + case 0b100000: uart_puts("Instruction abort, lower EL"); break; + case 0b100001: uart_puts("Instruction abort, same EL"); break; + case 0b100010: uart_puts("Instruction alignment fault"); break; + case 0b100100: uart_puts("Data abort, lower EL"); break; + case 0b100101: uart_puts("Data abort, same EL"); break; + case 0b100110: uart_puts("Stack alignment fault"); break; + case 0b101100: uart_puts("Floating point"); break; + default: uart_puts("Unknown"); break; + } + // decode data abort cause + if(esr>>26==0b100100 || esr>>26==0b100101) { + uart_puts(", "); + switch((esr>>2)&0x3) { + case 0: uart_puts("Address size fault"); break; + case 1: uart_puts("Translation fault"); break; + case 2: uart_puts("Access flag fault"); break; + case 3: uart_puts("Permission fault"); break; + } + switch(esr&0x3) { + case 0: uart_puts(" at level 0"); break; + case 1: uart_puts(" at level 1"); break; + case 2: uart_puts(" at level 2"); break; + case 3: uart_puts(" at level 3"); break; + } + } + // dump registers + uart_puts(":\n ESR_EL1 "); + uart_hex(esr>>32); + uart_hex(esr); + uart_puts(" ELR_EL1 "); + uart_hex(elr>>32); + uart_hex(elr); + uart_puts("\n SPSR_EL1 "); + uart_hex(spsr>>32); + uart_hex(spsr); + uart_puts(" FAR_EL1 "); + uart_hex(far>>32); + uart_hex(far); + uart_puts("\n"); + // no return from exception for now + while(1); +} diff --git a/11_exceptions/gpio.h b/11_exceptions/gpio.h new file mode 100644 index 00000000..52fa671d --- /dev/null +++ b/11_exceptions/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/11_exceptions/kernel8.img b/11_exceptions/kernel8.img new file mode 100755 index 0000000000000000000000000000000000000000..84dcf62cb0481dce6656d58e66713d4991b40c9f GIT binary patch literal 8248 zcmeHLUu;{|8UOAdJ8t3@*9016(R`eil|^W@P)L@c`6g|m1yzjRcu+Bk_||bl6xU8{ zXDzEV-?*hrjG>&s)~Q0oX<@8>s;Uaj(zGTZp*>C8t<2LT9IYFh_T(@q-kN&9a~-#7 zRvuUF;aa*r-|u|?&iA|DIlk8m)Kdzo+MGdjX@n`ITCKLt*iQ$w{+?36M-@}1u+-O4 zqU9$_q-qywxucXV1JebID0`8%Lf-mBNv0V~ZvW+q>}xA6JV^(o#kNxJm}$vcN9hoe zuM=Zgng1w6#FvNYpgcrvIifwGlk`QuN(au?YL9g*^v1`?AHX`C%i+N30jCF?9&mcV z>4E=U4-lD_r1z9MwVslKOO5oDMkH#zTb#2yv98Ifb7 z{Q_(VbzEJ{S?bkySE6Oq<s`4#DGTPb+%lodSp-b$w_7y4OS>En=sXIkO}8PB$y zVVwV#QlIzrl$Mm--11wOSBRunf_T1_+VVm!5T0>`@1ipD(dzNb=Oyq%?wr-6n)<4O zx>T)7SpOi+>Mu#A9v~_nrhH0D7=aFJUp>C`E5V7#FDvz!LKf>>sy*B-QO*)E7-BT+B-n{LVaH&%Slii6u`?0oPO`O0F% zS{X)r&y_dvGs4cT%?UeO4?Ce3c4g$X?IJCFwh=qx=rV zZr3wQ`AxhN`niU^*~GsJ430(oS<+m*9r#cKn=XDo@be9vcX2=Pa}BI*;#+`!1T5cs z+7kOfF4xb3`k7Jdc7x}p*3(uK=5faOKfu{4Y*pWBOW6KJQM&M((4|6N#=g6?53hC4 zV1I3g56;AiKAeTYc!&QoNfXPse;DI+l* zkFjKmJ^DC1G@fC`=x8dIPP6o+5sk4#GQ-l-lat9*CN|oP`t8r~i;3t9sbnHKowo6i ze!w0Fhw9_-Kq{3?5%n^An!cBqNFqDDM!&kQBfnbdStSTN%d*76XGCy&NbY+(PF>C?uMSVK*>`Nzk{ z5=UZ*3_EO0$1}G7J|kn?De(IF^#O-7Ms$K1{}pL4o-{J!i7_^r98Vy0UxUl>AI8?D z6Fel+ahRf>TdRP5G%Bb+95=>pn}0f%Ix?P4Z!{-nWLP}*gIJvHvg^2ocW=OtY`~A& zxVM?Hfnj}QVE=9=CP3IN0Nl)mpI)aXHrRK&UO3_N5VHs8%VEG_z+u2)z+u2)z+u2) dz+u2)z+vG3hJnWa%Cz?XGVNOX-}y^c_#cTNFe(55 literal 0 HcmV?d00001 diff --git a/11_exceptions/link.ld b/11_exceptions/link.ld new file mode 100644 index 00000000..bfddd76f --- /dev/null +++ b/11_exceptions/link.ld @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +SECTIONS +{ + . = 0x80000; + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + . = ALIGN(4096); + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + . = ALIGN(4096); + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; diff --git a/11_exceptions/main.c b/11_exceptions/main.c new file mode 100644 index 00000000..93f473c3 --- /dev/null +++ b/11_exceptions/main.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "uart.h" +#include "mmu.h" + +void main() +{ + unsigned int r; + + // set up serial console + uart_init(); + + // set up paging + mmu_init(); + + // generate a Data Abort with a bad address access + r=*((volatile unsigned int*)0xFFFFFFFFFF000000); + // make gcc happy about unused variables :-) + r++; + + // echo everything back + while(1) { + uart_send(uart_getc()); + } +} diff --git a/11_exceptions/mbox.c b/11_exceptions/mbox.c new file mode 100644 index 00000000..f750c3e4 --- /dev/null +++ b/11_exceptions/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/11_exceptions/mbox.h b/11_exceptions/mbox.h new file mode 100644 index 00000000..09844dea --- /dev/null +++ b/11_exceptions/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/11_exceptions/mmu.c b/11_exceptions/mmu.c new file mode 100644 index 00000000..dae1dbb9 --- /dev/null +++ b/11_exceptions/mmu.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "gpio.h" // get MMIO_BASE +#include "uart.h" + +#define PAGESIZE 4096 + +// granularity +#define PT_PAGE 0b11 // 4k granule +#define PT_BLOCK 0b01 // 2M granule +// accessibility +#define PT_KERNEL (0<<6) // privileged, supervisor EL1 access only +#define PT_USER (1<<6) // unprivileged, EL0 access allowed +#define PT_RW (0<<7) // read-write +#define PT_RO (1<<7) // read-only +#define PT_AF (1<<10) // accessed flag +#define PT_NX (1UL<<54) // no execute +// shareability +#define PT_OSH (2<<8) // outter shareable +#define PT_ISH (3<<8) // inner shareable +// defined in MAIR register +#define PT_MEM (0<<2) // normal memory +#define PT_DEV (1<<2) // device MMIO +#define PT_NC (2<<2) // non-cachable + +#define TTBR_ENABLE 1 + +// get addresses from linker +extern volatile unsigned char _data; +extern volatile unsigned char _end; + +/** + * Set up page translation tables and enable virtual memory + */ +void mmu_init() +{ + unsigned long r, b, *paging=(unsigned long*)&_end; + + /* create MMU translation tables at _end */ + + // TTBR0, identity L1 + paging[0]=(unsigned long)((unsigned char*)&_end+2*PAGESIZE) | // physical address + PT_PAGE | // it has the "Present" flag, which must be set, and we have area in it mapped by pages + PT_AF | // accessed flag. Without this we're going to have a Data Abort exception + PT_USER | // non-privileged + PT_ISH | // inner shareable + PT_MEM; // normal memory + + // identity L2, first 2M block + paging[2*512]=(unsigned long)((unsigned char*)&_end+3*PAGESIZE) | // physical address + PT_PAGE | // we have area in it mapped by pages + PT_AF | // accessed flag + PT_USER | // non-privileged + PT_ISH | // inner shareable + PT_MEM; // normal memory + + // identity L2 2M blocks + b=MMIO_BASE>>21; + // skip 0th, as we're about to map it by L3 + for(r=1;r<512;r++) + paging[2*512+r]=(unsigned long)((r<<21)) | // physical address + PT_BLOCK | // map 2M block + PT_AF | // accessed flag + PT_NX | // no execute + PT_USER | // non-privileged + (r>=b? PT_OSH|PT_DEV : PT_ISH|PT_MEM); // different attributes for device memory + + // identity L3 + for(r=0;r<512;r++) + paging[3*512+r]=(unsigned long)(r*PAGESIZE) | // physical address + PT_PAGE | // map 4k + PT_AF | // accessed flag + PT_USER | // non-privileged + PT_ISH | // inner shareable + ((r<0x80||r>(unsigned long)&_data/PAGESIZE)? PT_RW|PT_NX : PT_RO); // different for code and data + + // TTBR1, kernel L1 + paging[512+511]=(unsigned long)((unsigned char*)&_end+4*PAGESIZE) | // physical address + PT_PAGE | // we have area in it mapped by pages + PT_AF | // accessed flag + PT_KERNEL | // privileged + PT_ISH | // inner shareable + PT_MEM; // normal memory + + // kernel L2 + paging[4*512+511]=(unsigned long)((unsigned char*)&_end+5*PAGESIZE) | // physical address + PT_PAGE | // we have area in it mapped by pages + PT_AF | // accessed flag + PT_KERNEL | // privileged + PT_ISH | // inner shareable + PT_MEM; // normal memory + + // kernel L3 + paging[5*512]=(unsigned long)(MMIO_BASE+0x00201000) | // physical address + PT_PAGE | // map 4k + PT_AF | // accessed flag + PT_NX | // no execute + PT_KERNEL | // privileged + PT_OSH | // outter shareable + PT_DEV; // device memory + + /* okay, now we have to set system registers to enable MMU */ + + // check for 4k granule and at least 36 bits physical address bus */ + asm volatile ("mrs %0, id_aa64mmfr0_el1" : "=r" (r)); + b=r&0xF; + if(r&(0xF<<28)/*4k*/ || b<1/*36 bits*/) { + uart_puts("ERROR: 4k granule or 36 bit address space not supported\n"); + return; + } + + // first, set Memory Attributes array, indexed by PT_MEM, PT_DEV, PT_NC in our example + r= (0xFF << 0) | // AttrIdx=0: normal, IWBWA, OWBWA, NTR + (0x04 << 8) | // AttrIdx=1: device, nGnRE (must be OSH too) + (0x44 <<16); // AttrIdx=2: non cacheable + asm volatile ("msr mair_el1, %0" : : "r" (r)); + + // next, specify mapping characteristics in translate control register + r= (0b00LL << 37) | // TBI=0, no tagging + (b << 32) | // IPS=autodetected + (0b10LL << 30) | // TG1=4k + (0b11LL << 28) | // SH1=3 inner + (0b01LL << 26) | // ORGN1=1 write back + (0b01LL << 24) | // IRGN1=1 write back + (0b0LL << 23) | // EPD1 enable higher half + (25LL << 16) | // T1SZ=25, 3 levels (512G) + (0b00LL << 14) | // TG0=4k + (0b11LL << 12) | // SH0=3 inner + (0b01LL << 10) | // ORGN0=1 write back + (0b01LL << 8) | // IRGN0=1 write back + (0b0LL << 7) | // EPD0 enable lower half + (25LL << 0); // T0SZ=25, 3 levels (512G) + asm volatile ("msr tcr_el1, %0; isb" : : "r" (r)); + + // tell the MMU where our translation tables are. TTBR_ENABLE bit not documented, but required + // lower half, user space + asm volatile ("msr ttbr0_el1, %0" : : "r" ((unsigned long)&_end + TTBR_ENABLE)); + // upper half, kernel space + asm volatile ("msr ttbr1_el1, %0" : : "r" ((unsigned long)&_end + TTBR_ENABLE + PAGESIZE)); + + // finally, toggle some bits in system control register to enable page translation + asm volatile ("dsb ish; isb; mrs %0, sctlr_el1" : "=r" (r)); + r|=0xC00800; // set mandatory reserved bits + r&=~((1<<25) | // clear EE, little endian translation tables + (1<<24) | // clear E0E + (1<<19) | // clear WXN + (1<<12) | // clear I, no instruction cache + (1<<4) | // clear SA0 + (1<<3) | // clear SA + (1<<2) | // clear C, no cache at all + (1<<1)); // clear A, no aligment check + r|= (1<<0); // set M, enable MMU + asm volatile ("msr sctlr_el1, %0; isb" : : "r" (r)); +} diff --git a/11_exceptions/mmu.h b/11_exceptions/mmu.h new file mode 100644 index 00000000..7c3684e7 --- /dev/null +++ b/11_exceptions/mmu.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +void mmu_init(); diff --git a/11_exceptions/start.S b/11_exceptions/start.S new file mode 100644 index 00000000..4de3be0a --- /dev/null +++ b/11_exceptions/start.S @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +.section ".text.boot" + +.global _start + +_start: + // read cpu id, stop slave cores + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // cpu id > 0, stop +1: wfe + b 1b +2: // cpu id == 0 + + // set stack before our code + ldr x1, =_start + + // set up EL1 + mrs x0, CurrentEL + cmp x0, #4 + beq 5f + msr sp_el1, x1 + // enable CNTP for EL1 + mrs x0, cnthctl_el2 + orr x0, x0, #3 + msr cnthctl_el2, x0 + msr cntvoff_el2, xzr + // Setup SCTLR access + mov x0, #(1 << 31) // AArch64 + orr x0, x0, #(1 << 1) // SWIO hardwired on Pi3 + msr hcr_el2, x0 + mrs x0, hcr_el2 + mov x2, #0x0800 + movk x2, #0x30d0, lsl #16 + msr sctlr_el1, x2 + // set up exception handlers + ldr x1, =_vectors + msr vbar_el1, x1 + // change execution level to EL1 + mov x2, #0x3c4 + msr spsr_el2, x2 + adr x2, 5f + msr elr_el2, x2 + eret + +5: mov sp, x1 + + // clear bss + ldr x1, =__bss_start + ldr w2, =__bss_size +3: cbz w2, 4f + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b + + // jump to C code, should not return +4: bl main + // for failsafe, halt this core too + b 1b + + // important, code has to be properly aligned + .align 11 +_vectors: + // synchronous + .align 7 + mov x0, #0 + mrs x1, esr_el1 + mrs x2, elr_el1 + mrs x3, spsr_el1 + mrs x4, far_el1 + b exc_handler + + // IRQ + .align 7 + mov x0, #1 + mrs x1, esr_el1 + mrs x2, elr_el1 + mrs x3, spsr_el1 + mrs x4, far_el1 + b exc_handler + + // FIQ + .align 7 + mov x0, #2 + mrs x1, esr_el1 + mrs x2, elr_el1 + mrs x3, spsr_el1 + mrs x4, far_el1 + b exc_handler + + // SError + .align 7 + mov x0, #3 + mrs x1, esr_el1 + mrs x2, elr_el1 + mrs x3, spsr_el1 + mrs x4, far_el1 + b exc_handler diff --git a/11_exceptions/uart.c b/11_exceptions/uart.c new file mode 100644 index 00000000..d368d399 --- /dev/null +++ b/11_exceptions/uart.c @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2018 bzt (bztsrc@github) + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + */ + +#include "gpio.h" +#include "mbox.h" + +/* PL011 UART registers */ +#define UART0_DR ((volatile unsigned int*)(MMIO_BASE+0x00201000)) +#define UART0_FR ((volatile unsigned int*)(MMIO_BASE+0x00201018)) +#define UART0_IBRD ((volatile unsigned int*)(MMIO_BASE+0x00201024)) +#define UART0_FBRD ((volatile unsigned int*)(MMIO_BASE+0x00201028)) +#define UART0_LCRH ((volatile unsigned int*)(MMIO_BASE+0x0020102C)) +#define UART0_CR ((volatile unsigned int*)(MMIO_BASE+0x00201030)) +#define UART0_IMSC ((volatile unsigned int*)(MMIO_BASE+0x00201038)) +#define UART0_ICR ((volatile unsigned int*)(MMIO_BASE+0x00201044)) + +/** + * Set baud rate and characteristics (115200 8N1) and map to GPIO + */ +void uart_init() +{ + register unsigned int r; + + /* initialize UART */ + *UART0_CR = 0; // turn off UART0 + + /* set up clock for consistent divisor values */ + mbox[0] = 8*4; + mbox[1] = MBOX_REQUEST; + mbox[2] = MBOX_TAG_SETCLKRATE; // set clock rate + mbox[3] = 12; + mbox[4] = 8; + mbox[5] = 2; // UART clock + mbox[6] = 4000000; // 4Mhz + mbox[7] = MBOX_TAG_LAST; + mbox_call(MBOX_CH_PROP); + + /* map UART0 to GPIO pins */ + r=*GPFSEL1; + r&=~((7<<12)|(7<<15)); // gpio14, gpio15 + r|=(2<<12)|(2<<15); // alt5 + *GPFSEL1 = r; + *GPPUD = 0; // enable pins 14 and 15 + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = (1<<14)|(1<<15); + r=150; while(r--) { asm volatile("nop"); } + *GPPUDCLK0 = 0; // flush GPIO setup + + *UART0_ICR = 0x7FF; // clear interrupts + *UART0_IBRD = 2; // 115200 baud + *UART0_FBRD = 0xB; + *UART0_LCRH = 0b11<<5; // 8n1 + *UART0_CR = 0x301; // enable Tx, Rx, FIFO +} + +/** + * Send a character + */ +void uart_send(unsigned int c) { + /* wait until we can send */ + do{asm volatile("nop");}while(*UART0_FR&0x20); + /* write the character to the buffer */ + *UART0_DR=c; +} + +/** + * Receive a character + */ +char uart_getc() { + char r; + /* wait until something is in the buffer */ + do{asm volatile("nop");}while(*UART0_FR&0x10); + /* read it and return */ + r=(char)(*UART0_DR); + /* convert carrige return to newline */ + return r=='\r'?'\n':r; +} + +/** + * Display a string + */ +void uart_puts(char *s) { + while(*s) { + /* convert newline to carrige return + newline */ + if(*s=='\n') + uart_send('\r'); + uart_send(*s++); + } +} + +/** + * Display a binary value in hexadecimal + */ +void uart_hex(unsigned int d) { + unsigned int n; + int c; + for(c=28;c>=0;c-=4) { + // get highest tetrad + n=(d>>c)&0xF; + // 0-9 => '0'-'9', 10-15 => 'A'-'F' + n+=n>9?0x37:0x30; + uart_send(n); + } +} diff --git a/11_exceptions/uart.h b/11_exceptions/uart.h new file mode 100644 index 00000000..99b2be48 --- /dev/null +++ b/11_exceptions/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);