Fixed typos and more tutorials

pull/4/head
bzt 6 years ago
parent 22fc0181a3
commit 2fc348ba46

@ -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.

@ -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

@ -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.

@ -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

@ -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ő.

@ -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.

@ -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);
}

@ -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))

Binary file not shown.

@ -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;

@ -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());
}
}

@ -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;
}

@ -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);

@ -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));
}

@ -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();

@ -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

@ -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);
}
}

@ -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);
Loading…
Cancel
Save