diff --git a/exercises/lesson03/1/bl4ckout31/Makefile b/exercises/lesson03/1/bl4ckout31/Makefile new file mode 100644 index 00000000..4f92a490 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/Makefile @@ -0,0 +1,31 @@ +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude -mgeneral-regs-only +ASMOPS = -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : kernel8.img + +clean : + rm -rf $(BUILD_DIR) *.img + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: $(SRC_DIR)/linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img diff --git a/exercises/lesson03/1/bl4ckout31/build.bat b/exercises/lesson03/1/bl4ckout31/build.bat new file mode 100755 index 00000000..26eb1b5e --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/build.bat @@ -0,0 +1 @@ +docker run --rm -v %cd%:/app -w /app smatyukevich/raspberry-pi-os-builder make %1 diff --git a/exercises/lesson03/1/bl4ckout31/build.sh b/exercises/lesson03/1/bl4ckout31/build.sh new file mode 100755 index 00000000..56cbff29 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker run --rm -v $(pwd):/app -w /app smatyukevich/raspberry-pi-os-builder make $1 diff --git a/exercises/lesson03/1/bl4ckout31/include/arm/sysregs.h b/exercises/lesson03/1/bl4ckout31/include/arm/sysregs.h new file mode 100644 index 00000000..90853534 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/arm/sysregs.h @@ -0,0 +1,42 @@ +#ifndef _SYSREGS_H +#define _SYSREGS_H + +// *************************************** +// SCTLR_EL1, System Control Register (EL1), Page 2654 of AArch64-Reference-Manual. +// *************************************** + +#define SCTLR_RESERVED (3 << 28) | (3 << 22) | (1 << 20) | (1 << 11) +#define SCTLR_EE_LITTLE_ENDIAN (0 << 25) +#define SCTLR_EOE_LITTLE_ENDIAN (0 << 24) +#define SCTLR_I_CACHE_DISABLED (0 << 12) +#define SCTLR_D_CACHE_DISABLED (0 << 2) +#define SCTLR_MMU_DISABLED (0 << 0) +#define SCTLR_MMU_ENABLED (1 << 0) + +#define SCTLR_VALUE_MMU_DISABLED (SCTLR_RESERVED | SCTLR_EE_LITTLE_ENDIAN | SCTLR_I_CACHE_DISABLED | SCTLR_D_CACHE_DISABLED | SCTLR_MMU_DISABLED) + +// *************************************** +// HCR_EL2, Hypervisor Configuration Register (EL2), Page 2487 of AArch64-Reference-Manual. +// *************************************** + +#define HCR_RW (1 << 31) +#define HCR_VALUE HCR_RW + +// *************************************** +// SCR_EL3, Secure Configuration Register (EL3), Page 2648 of AArch64-Reference-Manual. +// *************************************** + +#define SCR_RESERVED (3 << 4) +#define SCR_RW (1 << 10) +#define SCR_NS (1 << 0) +#define SCR_VALUE (SCR_RESERVED | SCR_RW | SCR_NS) + +// *************************************** +// SPSR_EL3, Saved Program Status Register (EL3) Page 389 of AArch64-Reference-Manual. +// *************************************** + +#define SPSR_MASK_ALL (7 << 6) +#define SPSR_EL1h (5 << 0) +#define SPSR_VALUE (SPSR_MASK_ALL | SPSR_EL1h) + +#endif diff --git a/exercises/lesson03/1/bl4ckout31/include/entry.h b/exercises/lesson03/1/bl4ckout31/include/entry.h new file mode 100644 index 00000000..cb800cfe --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/entry.h @@ -0,0 +1,26 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#define S_FRAME_SIZE 256 // size of all saved registers + +#define SYNC_INVALID_EL1t 0 +#define IRQ_INVALID_EL1t 1 +#define FIQ_INVALID_EL1t 2 +#define ERROR_INVALID_EL1t 3 + +#define SYNC_INVALID_EL1h 4 +#define IRQ_INVALID_EL1h 5 +#define FIQ_INVALID_EL1h 6 +#define ERROR_INVALID_EL1h 7 + +#define SYNC_INVALID_EL0_64 8 +#define IRQ_INVALID_EL0_64 9 +#define FIQ_INVALID_EL0_64 10 +#define ERROR_INVALID_EL0_64 11 + +#define SYNC_INVALID_EL0_32 12 +#define IRQ_INVALID_EL0_32 13 +#define FIQ_INVALID_EL0_32 14 +#define ERROR_INVALID_EL0_32 15 + +#endif diff --git a/exercises/lesson03/1/bl4ckout31/include/irq.h b/exercises/lesson03/1/bl4ckout31/include/irq.h new file mode 100644 index 00000000..0e35437b --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/irq.h @@ -0,0 +1,10 @@ +#ifndef _IRQ_H +#define _IRQ_H + +void enable_interrupt_controller( void ); + +void irq_vector_init( void ); +void enable_irq( void ); +void disable_irq( void ); + +#endif /*_IRQ_H */ diff --git a/exercises/lesson03/1/bl4ckout31/include/mini_uart.h b/exercises/lesson03/1/bl4ckout31/include/mini_uart.h new file mode 100644 index 00000000..e3bd1372 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/mini_uart.h @@ -0,0 +1,9 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +void uart_init ( void ); +char uart_recv ( void ); +void uart_send ( char c ); +void putc ( void* p, char c ); + +#endif /*_MINI_UART_H */ diff --git a/exercises/lesson03/1/bl4ckout31/include/mm.h b/exercises/lesson03/1/bl4ckout31/include/mm.h new file mode 100644 index 00000000..784ac4b8 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/mm.h @@ -0,0 +1,19 @@ +#ifndef _MM_H +#define _MM_H + +#define PAGE_SHIFT 12 +#define TABLE_SHIFT 9 +#define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) + +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define SECTION_SIZE (1 << SECTION_SHIFT) + +#define LOW_MEMORY (2 * SECTION_SIZE) + +#ifndef __ASSEMBLER__ + +void memzero(unsigned long src, unsigned long n); + +#endif + +#endif /*_MM_H */ diff --git a/exercises/lesson03/1/bl4ckout31/include/peripherals/base.h b/exercises/lesson03/1/bl4ckout31/include/peripherals/base.h new file mode 100644 index 00000000..2ef4c57b --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/peripherals/base.h @@ -0,0 +1,7 @@ +#ifndef _P_BASE_H +#define _P_BASE_H + +#define PBASE 0x3F000000 +#define LPBASE 0x40000000 + +#endif /*_P_BASE_H */ diff --git a/exercises/lesson03/1/bl4ckout31/include/peripherals/gpio.h b/exercises/lesson03/1/bl4ckout31/include/peripherals/gpio.h new file mode 100644 index 00000000..5e9af26a --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/peripherals/gpio.h @@ -0,0 +1,12 @@ +#ifndef _P_GPIO_H +#define _P_GPIO_H + +#include "peripherals/base.h" + +#define GPFSEL1 (PBASE+0x00200004) +#define GPSET0 (PBASE+0x0020001C) +#define GPCLR0 (PBASE+0x00200028) +#define GPPUD (PBASE+0x00200094) +#define GPPUDCLK0 (PBASE+0x00200098) + +#endif /*_P_GPIO_H */ diff --git a/exercises/lesson03/1/bl4ckout31/include/peripherals/irq.h b/exercises/lesson03/1/bl4ckout31/include/peripherals/irq.h new file mode 100644 index 00000000..1d35eb51 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/peripherals/irq.h @@ -0,0 +1,28 @@ +#ifndef _P_IRQ_H +#define _P_IRQ_H + +#include "peripherals/base.h" + +#define IRQ_BASIC_PENDING (PBASE+0x0000B200) +#define IRQ_PENDING_1 (PBASE+0x0000B204) +#define IRQ_PENDING_2 (PBASE+0x0000B208) +#define FIQ_CONTROL (PBASE+0x0000B20C) +#define ENABLE_IRQS_1 (PBASE+0x0000B210) +#define ENABLE_IRQS_2 (PBASE+0x0000B214) +#define ENABLE_BASIC_IRQS (PBASE+0x0000B218) +#define DISABLE_IRQS_1 (PBASE+0x0000B21C) +#define DISABLE_IRQS_2 (PBASE+0x0000B220) +#define DISABLE_BASIC_IRQS (PBASE+0x0000B224) + +#define SYSTEM_TIMER_IRQ_0 (1 << 0) +#define SYSTEM_TIMER_IRQ_1 (1 << 1) +#define SYSTEM_TIMER_IRQ_2 (1 << 2) +#define SYSTEM_TIMER_IRQ_3 (1 << 3) + +// See BCM2836 ARM-local peripherals at +// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf + +#define CORE0_INTERRUPT_SOURCES (LPBASE+0x60) +#define LTIMER_INTERRUPT (1 << 11) + +#endif /*_P_IRQ_H */ diff --git a/exercises/lesson03/1/bl4ckout31/include/peripherals/mini_uart.h b/exercises/lesson03/1/bl4ckout31/include/peripherals/mini_uart.h new file mode 100644 index 00000000..af95a3be --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/peripherals/mini_uart.h @@ -0,0 +1,19 @@ +#ifndef _P_MINI_UART_H +#define _P_MINI_UART_H + +#include "peripherals/base.h" + +#define AUX_ENABLES (PBASE+0x00215004) +#define AUX_MU_IO_REG (PBASE+0x00215040) +#define AUX_MU_IER_REG (PBASE+0x00215044) +#define AUX_MU_IIR_REG (PBASE+0x00215048) +#define AUX_MU_LCR_REG (PBASE+0x0021504C) +#define AUX_MU_MCR_REG (PBASE+0x00215050) +#define AUX_MU_LSR_REG (PBASE+0x00215054) +#define AUX_MU_MSR_REG (PBASE+0x00215058) +#define AUX_MU_SCRATCH (PBASE+0x0021505C) +#define AUX_MU_CNTL_REG (PBASE+0x00215060) +#define AUX_MU_STAT_REG (PBASE+0x00215064) +#define AUX_MU_BAUD_REG (PBASE+0x00215068) + +#endif /*_P_MINI_UART_H */ diff --git a/exercises/lesson03/1/bl4ckout31/include/peripherals/timer.h b/exercises/lesson03/1/bl4ckout31/include/peripherals/timer.h new file mode 100644 index 00000000..6e078fcc --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/peripherals/timer.h @@ -0,0 +1,31 @@ +#ifndef _P_TIMER_H +#define _P_TIMER_H + +#include "peripherals/base.h" + +#define TIMER_CS (PBASE+0x00003000) +#define TIMER_CLO (PBASE+0x00003004) +#define TIMER_CHI (PBASE+0x00003008) +#define TIMER_C0 (PBASE+0x0000300C) +#define TIMER_C1 (PBASE+0x00003010) +#define TIMER_C2 (PBASE+0x00003014) +#define TIMER_C3 (PBASE+0x00003018) + +#define TIMER_CS_M0 (1 << 0) +#define TIMER_CS_M1 (1 << 1) +#define TIMER_CS_M2 (1 << 2) +#define TIMER_CS_M3 (1 << 3) + +// See BCM2836 ARM-local peripherals at +// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf + +#define LTIMER_CTRL (LPBASE+0x34) +#define LTIMER_CLR (LPBASE+0x38) + +#define LTIMER_CTRL_EN (1 << 28) +#define LTIMER_CTRL_INT_EN (1 << 29) +#define LTIMER_CTRL_VALUE (LTIMER_CTRL_EN | LTIMER_CTRL_INT_EN) + +#define LTIMER_CLR_ACK (1 << 31) + +#endif /*_P_TIMER_H */ diff --git a/exercises/lesson03/1/bl4ckout31/include/printf.h b/exercises/lesson03/1/bl4ckout31/include/printf.h new file mode 100644 index 00000000..f37c1bf2 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/printf.h @@ -0,0 +1,106 @@ +/* +File: printf.h + +Copyright (C) 2004 Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +This library is realy just two files: 'printf.h' and 'printf.c'. + +They provide a simple and small (+200 loc) printf functionality to +be used in embedded systems. + +I've found them so usefull in debugging that I do not bother with a +debugger at all. + +They are distributed in source form, so to use them, just compile them +into your project. + +Two printf variants are provided: printf and sprintf. + +The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'. + +Zero padding and field width are also supported. + +If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the +long specifier is also +supported. Note that this will pull in some long math routines (pun intended!) +and thus make your executable noticably longer. + +The memory foot print of course depends on the target cpu, compiler and +compiler options, but a rough guestimate (based on a H8S target) is about +1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space. +Not too bad. Your milage may vary. By hacking the source code you can +get rid of some hunred bytes, I'm sure, but personally I feel the balance of +functionality and flexibility versus code size is close to optimal for +many embedded systems. + +To use the printf you need to supply your own character output function, +something like : + + void putc ( void* p, char c) + { + while (!SERIAL_PORT_EMPTY) ; + SERIAL_PORT_TX_REGISTER = c; + } + +Before you can call printf you need to initialize it to use your +character output function with something like: + + init_printf(NULL,putc); + +Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', +the NULL (or any pointer) you pass into the 'init_printf' will eventually be +passed to your 'putc' routine. This allows you to pass some storage space (or +anything realy) to the character output function, if necessary. +This is not often needed but it was implemented like that because it made +implementing the sprintf function so neat (look at the source code). + +The code is re-entrant, except for the 'init_printf' function, so it +is safe to call it from interupts too, although this may result in mixed output. +If you rely on re-entrancy, take care that your 'putc' function is re-entrant! + +The printf and sprintf functions are actually macros that translate to +'tfp_printf' and 'tfp_sprintf'. This makes it possible +to use them along with 'stdio.h' printf's in a single source file. +You just need to undef the names before you include the 'stdio.h'. +Note that these are not function like macros, so if you have variables +or struct members with these names, things will explode in your face. +Without variadic macros this is the best we can do to wrap these +fucnction. If it is a problem just give up the macros and use the +functions directly or rename them. + +For further details see source code. + +regs Kusti, 23.10.2004 +*/ + + +#ifndef __TFP_PRINTF__ +#define __TFP_PRINTF__ + +#include + +void init_printf(void* putp,void (*putf) (void*,char)); + +void tfp_printf(char *fmt, ...); +void tfp_sprintf(char* s,char *fmt, ...); + +void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va); + +#define printf tfp_printf +#define sprintf tfp_sprintf + +#endif diff --git a/exercises/lesson03/1/bl4ckout31/include/timer.h b/exercises/lesson03/1/bl4ckout31/include/timer.h new file mode 100644 index 00000000..f8088c5e --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/timer.h @@ -0,0 +1,10 @@ +#ifndef _TIMER_H +#define _TIMER_H + +void timer_init ( void ); +void handle_timer_irq ( void ); + +void local_timer_init ( void ); +void handle_local_timer_irq ( void ); + +#endif /*_TIMER_H */ diff --git a/exercises/lesson03/1/bl4ckout31/include/utils.h b/exercises/lesson03/1/bl4ckout31/include/utils.h new file mode 100644 index 00000000..20fb61f2 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/include/utils.h @@ -0,0 +1,9 @@ +#ifndef _UTILS_H +#define _UTILS_H + +extern void delay ( unsigned long); +extern void put32 ( unsigned long, unsigned int ); +extern unsigned int get32 ( unsigned long ); +extern int get_el ( void ); + +#endif /*_UTILS_H */ diff --git a/exercises/lesson03/1/bl4ckout31/src/boot.S b/exercises/lesson03/1/bl4ckout31/src/boot.S new file mode 100644 index 00000000..6db1006e --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/src/boot.S @@ -0,0 +1,43 @@ +#include "arm/sysregs.h" + +#include "mm.h" + +.section ".text.boot" + +.globl _start +_start: + mrs x0, mpidr_el1 + and x0, x0,#0xFF // Check processor id + cbz x0, master // Hang for all non-primary CPU + b proc_hang + +proc_hang: + b proc_hang + +master: + ldr x0, =SCTLR_VALUE_MMU_DISABLED + msr sctlr_el1, x0 + + ldr x0, =HCR_VALUE + msr hcr_el2, x0 + + ldr x0, =SCR_VALUE + msr scr_el3, x0 + + ldr x0, =SPSR_VALUE + msr spsr_el3, x0 + + adr x0, el1_entry + msr elr_el3, x0 + + eret + +el1_entry: + adr x0, bss_begin + adr x1, bss_end + sub x1, x1, x0 + bl memzero + + mov sp, #LOW_MEMORY + bl kernel_main + b proc_hang // should never come here diff --git a/exercises/lesson03/1/bl4ckout31/src/config.txt b/exercises/lesson03/1/bl4ckout31/src/config.txt new file mode 100644 index 00000000..27934969 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/src/config.txt @@ -0,0 +1,2 @@ +kernel_old=1 +disable_commandline_tags=1 diff --git a/exercises/lesson03/1/bl4ckout31/src/entry.S b/exercises/lesson03/1/bl4ckout31/src/entry.S new file mode 100644 index 00000000..18a5e0c3 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/src/entry.S @@ -0,0 +1,136 @@ +#include "entry.h" + + .macro handle_invalid_entry type + kernel_entry + mov x0, #\type + mrs x1, esr_el1 + mrs x2, elr_el1 + bl show_invalid_entry_message + b err_hang + .endm + + .macro ventry label + .align 7 + b \label + .endm + + .macro kernel_entry + sub sp, sp, #S_FRAME_SIZE + stp x0, x1, [sp, #16 * 0] + stp x2, x3, [sp, #16 * 1] + stp x4, x5, [sp, #16 * 2] + stp x6, x7, [sp, #16 * 3] + stp x8, x9, [sp, #16 * 4] + stp x10, x11, [sp, #16 * 5] + stp x12, x13, [sp, #16 * 6] + stp x14, x15, [sp, #16 * 7] + stp x16, x17, [sp, #16 * 8] + stp x18, x19, [sp, #16 * 9] + stp x20, x21, [sp, #16 * 10] + stp x22, x23, [sp, #16 * 11] + stp x24, x25, [sp, #16 * 12] + stp x26, x27, [sp, #16 * 13] + stp x28, x29, [sp, #16 * 14] + str x30, [sp, #16 * 15] + .endm + + .macro kernel_exit + ldp x0, x1, [sp, #16 * 0] + ldp x2, x3, [sp, #16 * 1] + ldp x4, x5, [sp, #16 * 2] + ldp x6, x7, [sp, #16 * 3] + ldp x8, x9, [sp, #16 * 4] + ldp x10, x11, [sp, #16 * 5] + ldp x12, x13, [sp, #16 * 6] + ldp x14, x15, [sp, #16 * 7] + ldp x16, x17, [sp, #16 * 8] + ldp x18, x19, [sp, #16 * 9] + ldp x20, x21, [sp, #16 * 10] + ldp x22, x23, [sp, #16 * 11] + ldp x24, x25, [sp, #16 * 12] + ldp x26, x27, [sp, #16 * 13] + ldp x28, x29, [sp, #16 * 14] + ldr x30, [sp, #16 * 15] + add sp, sp, #S_FRAME_SIZE + eret + .endm + + +/* + * Exception vectors. + */ +.align 11 +.globl vectors +vectors: + ventry sync_invalid_el1t // Synchronous EL1t + ventry irq_invalid_el1t // IRQ EL1t + ventry fiq_invalid_el1t // FIQ EL1t + ventry error_invalid_el1t // Error EL1t + + ventry sync_invalid_el1h // Synchronous EL1h + ventry el1_irq // IRQ EL1h + ventry fiq_invalid_el1h // FIQ EL1h + ventry error_invalid_el1h // Error EL1h + + ventry sync_invalid_el0_64 // Synchronous 64-bit EL0 + ventry irq_invalid_el0_64 // IRQ 64-bit EL0 + ventry fiq_invalid_el0_64 // FIQ 64-bit EL0 + ventry error_invalid_el0_64 // Error 64-bit EL0 + + ventry sync_invalid_el0_32 // Synchronous 32-bit EL0 + ventry irq_invalid_el0_32 // IRQ 32-bit EL0 + ventry fiq_invalid_el0_32 // FIQ 32-bit EL0 + ventry error_invalid_el0_32 // Error 32-bit EL0 + +sync_invalid_el1t: + handle_invalid_entry SYNC_INVALID_EL1t + +irq_invalid_el1t: + handle_invalid_entry IRQ_INVALID_EL1t + +fiq_invalid_el1t: + handle_invalid_entry FIQ_INVALID_EL1t + +error_invalid_el1t: + handle_invalid_entry ERROR_INVALID_EL1t + +sync_invalid_el1h: + handle_invalid_entry SYNC_INVALID_EL1h + +fiq_invalid_el1h: + handle_invalid_entry FIQ_INVALID_EL1h + +error_invalid_el1h: + handle_invalid_entry ERROR_INVALID_EL1h + +sync_invalid_el0_64: + handle_invalid_entry SYNC_INVALID_EL0_64 + +irq_invalid_el0_64: + handle_invalid_entry IRQ_INVALID_EL0_64 + +fiq_invalid_el0_64: + handle_invalid_entry FIQ_INVALID_EL0_64 + +error_invalid_el0_64: + handle_invalid_entry ERROR_INVALID_EL0_64 + +sync_invalid_el0_32: + handle_invalid_entry SYNC_INVALID_EL0_32 + +irq_invalid_el0_32: + handle_invalid_entry IRQ_INVALID_EL0_32 + +fiq_invalid_el0_32: + handle_invalid_entry FIQ_INVALID_EL0_32 + +error_invalid_el0_32: + handle_invalid_entry ERROR_INVALID_EL0_32 + +el1_irq: + kernel_entry + bl handle_irq + kernel_exit + +.globl err_hang +err_hang: b err_hang diff --git a/exercises/lesson03/1/bl4ckout31/src/irq.S b/exercises/lesson03/1/bl4ckout31/src/irq.S new file mode 100644 index 00000000..1c10ed2b --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/src/irq.S @@ -0,0 +1,15 @@ +.globl irq_vector_init +irq_vector_init: + adr x0, vectors // load VBAR_EL1 with virtual + msr vbar_el1, x0 // vector table address + ret + +.globl enable_irq +enable_irq: + msr daifclr, #2 + ret + +.globl disable_irq +disable_irq: + msr daifset, #2 + ret diff --git a/exercises/lesson03/1/bl4ckout31/src/irq.c b/exercises/lesson03/1/bl4ckout31/src/irq.c new file mode 100644 index 00000000..d4772d7d --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/src/irq.c @@ -0,0 +1,57 @@ +#include "utils.h" +#include "printf.h" +#include "timer.h" +#include "entry.h" +#include "peripherals/irq.h" + +const char *entry_error_messages[] = { + "SYNC_INVALID_EL1t", + "IRQ_INVALID_EL1t", + "FIQ_INVALID_EL1t", + "ERROR_INVALID_EL1T", + + "SYNC_INVALID_EL1h", + "IRQ_INVALID_EL1h", + "FIQ_INVALID_EL1h", + "ERROR_INVALID_EL1h", + + "SYNC_INVALID_EL0_64", + "IRQ_INVALID_EL0_64", + "FIQ_INVALID_EL0_64", + "ERROR_INVALID_EL0_64", + + "SYNC_INVALID_EL0_32", + "IRQ_INVALID_EL0_32", + "FIQ_INVALID_EL0_32", + "ERROR_INVALID_EL0_32" +}; + +void enable_interrupt_controller() +{ + /** The local interrupt controller can't be enable or disable. + * Instead, we are supposed to rely on the interrupt sources + * registers to enable or disable their interrupts + * + * Neverless, we can still change wich core will receive the + * interrupts. They go to Core 0 IRQ by default, which is what + * we want. This function becomes effectively useless. + */ +} + +void show_invalid_entry_message(int type, unsigned long esr, unsigned long address) +{ + printf("%s, ESR: %x, address: %x\r\n", entry_error_messages[type], esr, address); +} + +void handle_irq(void) +{ + // Each Core has its own pending local intrrupts register + unsigned int irq = get32(CORE0_INTERRUPT_SOURCES); + switch (irq) { + case (LTIMER_INTERRUPT): + handle_local_timer_irq(); + break; + default: + printf("Unknown pending irq: %x\r\n", irq); + } +} \ No newline at end of file diff --git a/exercises/lesson03/1/bl4ckout31/src/kernel.c b/exercises/lesson03/1/bl4ckout31/src/kernel.c new file mode 100644 index 00000000..4b69af56 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/src/kernel.c @@ -0,0 +1,19 @@ +#include "printf.h" +#include "timer.h" +#include "irq.h" +#include "mini_uart.h" + + +void kernel_main(void) +{ + uart_init(); + init_printf(0, putc); + irq_vector_init(); + local_timer_init(); + enable_interrupt_controller(); + enable_irq(); + + while (1){ + uart_send(uart_recv()); + } +} diff --git a/exercises/lesson03/1/bl4ckout31/src/linker.ld b/exercises/lesson03/1/bl4ckout31/src/linker.ld new file mode 100644 index 00000000..16fe2acc --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/src/linker.ld @@ -0,0 +1,11 @@ +SECTIONS +{ + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + . = ALIGN(0x8); + bss_begin = .; + .bss : { *(.bss*) } + bss_end = .; +} diff --git a/exercises/lesson03/1/bl4ckout31/src/mini_uart.c b/exercises/lesson03/1/bl4ckout31/src/mini_uart.c new file mode 100644 index 00000000..988f4782 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/src/mini_uart.c @@ -0,0 +1,62 @@ +#include "utils.h" +#include "peripherals/mini_uart.h" +#include "peripherals/gpio.h" + +void uart_send ( char c ) +{ + while(1) { + if(get32(AUX_MU_LSR_REG)&0x20) + break; + } + put32(AUX_MU_IO_REG,c); +} + +char uart_recv ( void ) +{ + while(1) { + if(get32(AUX_MU_LSR_REG)&0x01) + break; + } + return(get32(AUX_MU_IO_REG)&0xFF); +} + +void uart_send_string(char* str) +{ + for (int i = 0; str[i] != '\0'; i ++) { + uart_send((char)str[i]); + } +} + +void uart_init ( void ) +{ + unsigned int selector; + + selector = get32(GPFSEL1); + selector &= ~(7<<12); // clean gpio14 + selector |= 2<<12; // set alt5 for gpio14 + selector &= ~(7<<15); // clean gpio15 + selector |= 2<<15; // set alt5 for gpio15 + put32(GPFSEL1,selector); + + put32(GPPUD,0); + delay(150); + put32(GPPUDCLK0,(1<<14)|(1<<15)); + delay(150); + put32(GPPUDCLK0,0); + + put32(AUX_ENABLES,1); //Enable mini uart (this also enables access to it registers) + put32(AUX_MU_CNTL_REG,0); //Disable auto flow control and disable receiver and transmitter (for now) + put32(AUX_MU_IER_REG,0); //Disable receive and transmit interrupts + put32(AUX_MU_LCR_REG,3); //Enable 8 bit mode + put32(AUX_MU_MCR_REG,0); //Set RTS line to be always high + put32(AUX_MU_BAUD_REG,270); //Set baud rate to 115200 + + put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver +} + + +// This function is required by printf function +void putc ( void* p, char c) +{ + uart_send(c); +} diff --git a/exercises/lesson03/1/bl4ckout31/src/mm.S b/exercises/lesson03/1/bl4ckout31/src/mm.S new file mode 100644 index 00000000..1bd32ff3 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/src/mm.S @@ -0,0 +1,6 @@ +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret diff --git a/exercises/lesson03/1/bl4ckout31/src/printf.c b/exercises/lesson03/1/bl4ckout31/src/printf.c new file mode 100644 index 00000000..1383039a --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/src/printf.c @@ -0,0 +1,233 @@ +/* +File: printf.c + +Copyright (C) 2004 Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "printf.h" + +typedef void (*putcf) (void*,char); +static putcf stdout_putf; +static void* stdout_putp; + + +#ifdef PRINTF_LONG_SUPPORT + +static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf) + { + int n=0; + unsigned int d=1; + while (num/d >= base) + d*=base; + while (d!=0) { + int dgt = num / d; + num%=d; + d/=base; + if (n || dgt>0|| d==0) { + *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); + ++n; + } + } + *bf=0; + } + +static void li2a (long num, char * bf) + { + if (num<0) { + num=-num; + *bf++ = '-'; + } + uli2a(num,10,0,bf); + } + +#endif + +static void ui2a(unsigned int num, unsigned int base, int uc,char * bf) + { + int n=0; + unsigned int d=1; + while (num/d >= base) + d*=base; + while (d!=0) { + int dgt = num / d; + num%= d; + d/=base; + if (n || dgt>0 || d==0) { + *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); + ++n; + } + } + *bf=0; + } + +static void i2a (int num, char * bf) + { + if (num<0) { + num=-num; + *bf++ = '-'; + } + ui2a(num,10,0,bf); + } + +static int a2d(char ch) + { + if (ch>='0' && ch<='9') + return ch-'0'; + else if (ch>='a' && ch<='f') + return ch-'a'+10; + else if (ch>='A' && ch<='F') + return ch-'A'+10; + else return -1; + } + +static char a2i(char ch, char** src,int base,int* nump) + { + char* p= *src; + int num=0; + int digit; + while ((digit=a2d(ch))>=0) { + if (digit>base) break; + num=num*base+digit; + ch=*p++; + } + *src=p; + *nump=num; + return ch; + } + +static void putchw(void* putp,putcf putf,int n, char z, char* bf) + { + char fc=z? '0' : ' '; + char ch; + char* p=bf; + while (*p++ && n > 0) + n--; + while (n-- > 0) + putf(putp,fc); + while ((ch= *bf++)) + putf(putp,ch); + } + +void tfp_format(void* putp,putcf putf,char *fmt, va_list va) + { + char bf[12]; + + char ch; + + + while ((ch=*(fmt++))) { + if (ch!='%') + putf(putp,ch); + else { + char lz=0; +#ifdef PRINTF_LONG_SUPPORT + char lng=0; +#endif + int w=0; + ch=*(fmt++); + if (ch=='0') { + ch=*(fmt++); + lz=1; + } + if (ch>='0' && ch<='9') { + ch=a2i(ch,&fmt,10,&w); + } +#ifdef PRINTF_LONG_SUPPORT + if (ch=='l') { + ch=*(fmt++); + lng=1; + } +#endif + switch (ch) { + case 0: + goto abort; + case 'u' : { +#ifdef PRINTF_LONG_SUPPORT + if (lng) + uli2a(va_arg(va, unsigned long int),10,0,bf); + else +#endif + ui2a(va_arg(va, unsigned int),10,0,bf); + putchw(putp,putf,w,lz,bf); + break; + } + case 'd' : { +#ifdef PRINTF_LONG_SUPPORT + if (lng) + li2a(va_arg(va, unsigned long int),bf); + else +#endif + i2a(va_arg(va, int),bf); + putchw(putp,putf,w,lz,bf); + break; + } + case 'x': case 'X' : +#ifdef PRINTF_LONG_SUPPORT + if (lng) + uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf); + else +#endif + ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf); + putchw(putp,putf,w,lz,bf); + break; + case 'c' : + putf(putp,(char)(va_arg(va, int))); + break; + case 's' : + putchw(putp,putf,w,0,va_arg(va, char*)); + break; + case '%' : + putf(putp,ch); + default: + break; + } + } + } + abort:; + } + + +void init_printf(void* putp,void (*putf) (void*,char)) + { + stdout_putf=putf; + stdout_putp=putp; + } + +void tfp_printf(char *fmt, ...) + { + va_list va; + va_start(va,fmt); + tfp_format(stdout_putp,stdout_putf,fmt,va); + va_end(va); + } + +static void putcp(void* p,char c) + { + *(*((char**)p))++ = c; + } + + + +void tfp_sprintf(char* s,char *fmt, ...) + { + va_list va; + va_start(va,fmt); + tfp_format(&s,putcp,fmt,va); + putcp(&s,0); + va_end(va); + } diff --git a/exercises/lesson03/1/bl4ckout31/src/timer.c b/exercises/lesson03/1/bl4ckout31/src/timer.c new file mode 100644 index 00000000..ade15196 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/src/timer.c @@ -0,0 +1,32 @@ +#include "utils.h" +#include "printf.h" +#include "peripherals/timer.h" + +const unsigned int interval = 9600000; +unsigned int curVal = 0; + +void timer_init ( void ) +{ + curVal = get32(TIMER_CLO); + curVal += interval; + put32(TIMER_C1, curVal); +} + +void handle_timer_irq( void ) +{ + curVal += interval; + put32(TIMER_C1, curVal); + put32(TIMER_CS, TIMER_CS_M1); + printf("Timer interrupt received\n\r"); +} + +void local_timer_init ( void ) +{ + put32(LTIMER_CTRL, (interval | LTIMER_CTRL_VALUE)); +} + +void handle_local_timer_irq( void ) +{ + printf("Timer interrupt received\n\r"); + put32(LTIMER_CLR, LTIMER_CLR_ACK); +} \ No newline at end of file diff --git a/exercises/lesson03/1/bl4ckout31/src/utils.S b/exercises/lesson03/1/bl4ckout31/src/utils.S new file mode 100644 index 00000000..44be4857 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/src/utils.S @@ -0,0 +1,21 @@ +.globl get_el +get_el: + mrs x0, CurrentEL + lsr x0, x0, #2 + ret + +.globl put32 +put32: + str w1,[x0] + ret + +.globl get32 +get32: + ldr w0,[x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret diff --git a/exercises/lesson03/1/bl4ckout31/start.sh b/exercises/lesson03/1/bl4ckout31/start.sh new file mode 100755 index 00000000..522e5563 --- /dev/null +++ b/exercises/lesson03/1/bl4ckout31/start.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +if [ $# -ne 1 ]; then + echo "usage: $0 kernel" + exit 1 +fi + +mount -L rpiboot /mnt +cp "$1" /mnt +umount /mnt diff --git a/exercises/lesson03/2/bl4ckout31/Makefile b/exercises/lesson03/2/bl4ckout31/Makefile new file mode 100644 index 00000000..4f92a490 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/Makefile @@ -0,0 +1,31 @@ +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude -mgeneral-regs-only +ASMOPS = -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : kernel8.img + +clean : + rm -rf $(BUILD_DIR) *.img + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: $(SRC_DIR)/linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img diff --git a/exercises/lesson03/2/bl4ckout31/build.bat b/exercises/lesson03/2/bl4ckout31/build.bat new file mode 100755 index 00000000..26eb1b5e --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/build.bat @@ -0,0 +1 @@ +docker run --rm -v %cd%:/app -w /app smatyukevich/raspberry-pi-os-builder make %1 diff --git a/exercises/lesson03/2/bl4ckout31/build.sh b/exercises/lesson03/2/bl4ckout31/build.sh new file mode 100755 index 00000000..56cbff29 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker run --rm -v $(pwd):/app -w /app smatyukevich/raspberry-pi-os-builder make $1 diff --git a/exercises/lesson03/2/bl4ckout31/include/arm/sysregs.h b/exercises/lesson03/2/bl4ckout31/include/arm/sysregs.h new file mode 100644 index 00000000..90853534 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/arm/sysregs.h @@ -0,0 +1,42 @@ +#ifndef _SYSREGS_H +#define _SYSREGS_H + +// *************************************** +// SCTLR_EL1, System Control Register (EL1), Page 2654 of AArch64-Reference-Manual. +// *************************************** + +#define SCTLR_RESERVED (3 << 28) | (3 << 22) | (1 << 20) | (1 << 11) +#define SCTLR_EE_LITTLE_ENDIAN (0 << 25) +#define SCTLR_EOE_LITTLE_ENDIAN (0 << 24) +#define SCTLR_I_CACHE_DISABLED (0 << 12) +#define SCTLR_D_CACHE_DISABLED (0 << 2) +#define SCTLR_MMU_DISABLED (0 << 0) +#define SCTLR_MMU_ENABLED (1 << 0) + +#define SCTLR_VALUE_MMU_DISABLED (SCTLR_RESERVED | SCTLR_EE_LITTLE_ENDIAN | SCTLR_I_CACHE_DISABLED | SCTLR_D_CACHE_DISABLED | SCTLR_MMU_DISABLED) + +// *************************************** +// HCR_EL2, Hypervisor Configuration Register (EL2), Page 2487 of AArch64-Reference-Manual. +// *************************************** + +#define HCR_RW (1 << 31) +#define HCR_VALUE HCR_RW + +// *************************************** +// SCR_EL3, Secure Configuration Register (EL3), Page 2648 of AArch64-Reference-Manual. +// *************************************** + +#define SCR_RESERVED (3 << 4) +#define SCR_RW (1 << 10) +#define SCR_NS (1 << 0) +#define SCR_VALUE (SCR_RESERVED | SCR_RW | SCR_NS) + +// *************************************** +// SPSR_EL3, Saved Program Status Register (EL3) Page 389 of AArch64-Reference-Manual. +// *************************************** + +#define SPSR_MASK_ALL (7 << 6) +#define SPSR_EL1h (5 << 0) +#define SPSR_VALUE (SPSR_MASK_ALL | SPSR_EL1h) + +#endif diff --git a/exercises/lesson03/2/bl4ckout31/include/entry.h b/exercises/lesson03/2/bl4ckout31/include/entry.h new file mode 100644 index 00000000..cb800cfe --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/entry.h @@ -0,0 +1,26 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#define S_FRAME_SIZE 256 // size of all saved registers + +#define SYNC_INVALID_EL1t 0 +#define IRQ_INVALID_EL1t 1 +#define FIQ_INVALID_EL1t 2 +#define ERROR_INVALID_EL1t 3 + +#define SYNC_INVALID_EL1h 4 +#define IRQ_INVALID_EL1h 5 +#define FIQ_INVALID_EL1h 6 +#define ERROR_INVALID_EL1h 7 + +#define SYNC_INVALID_EL0_64 8 +#define IRQ_INVALID_EL0_64 9 +#define FIQ_INVALID_EL0_64 10 +#define ERROR_INVALID_EL0_64 11 + +#define SYNC_INVALID_EL0_32 12 +#define IRQ_INVALID_EL0_32 13 +#define FIQ_INVALID_EL0_32 14 +#define ERROR_INVALID_EL0_32 15 + +#endif diff --git a/exercises/lesson03/2/bl4ckout31/include/irq.h b/exercises/lesson03/2/bl4ckout31/include/irq.h new file mode 100644 index 00000000..0e35437b --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/irq.h @@ -0,0 +1,10 @@ +#ifndef _IRQ_H +#define _IRQ_H + +void enable_interrupt_controller( void ); + +void irq_vector_init( void ); +void enable_irq( void ); +void disable_irq( void ); + +#endif /*_IRQ_H */ diff --git a/exercises/lesson03/2/bl4ckout31/include/mini_uart.h b/exercises/lesson03/2/bl4ckout31/include/mini_uart.h new file mode 100644 index 00000000..d2dd4cbc --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/mini_uart.h @@ -0,0 +1,11 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +void uart_init ( void ); +char uart_recv ( void ); +void uart_send ( char c ); +void putc ( void* p, char c ); + +void handle_uart_irq ( void ); + +#endif /*_MINI_UART_H */ diff --git a/exercises/lesson03/2/bl4ckout31/include/mm.h b/exercises/lesson03/2/bl4ckout31/include/mm.h new file mode 100644 index 00000000..784ac4b8 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/mm.h @@ -0,0 +1,19 @@ +#ifndef _MM_H +#define _MM_H + +#define PAGE_SHIFT 12 +#define TABLE_SHIFT 9 +#define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) + +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define SECTION_SIZE (1 << SECTION_SHIFT) + +#define LOW_MEMORY (2 * SECTION_SIZE) + +#ifndef __ASSEMBLER__ + +void memzero(unsigned long src, unsigned long n); + +#endif + +#endif /*_MM_H */ diff --git a/exercises/lesson03/2/bl4ckout31/include/peripherals/base.h b/exercises/lesson03/2/bl4ckout31/include/peripherals/base.h new file mode 100644 index 00000000..63f9c038 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/peripherals/base.h @@ -0,0 +1,6 @@ +#ifndef _P_BASE_H +#define _P_BASE_H + +#define PBASE 0x3F000000 + +#endif /*_P_BASE_H */ diff --git a/exercises/lesson03/2/bl4ckout31/include/peripherals/gpio.h b/exercises/lesson03/2/bl4ckout31/include/peripherals/gpio.h new file mode 100644 index 00000000..5e9af26a --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/peripherals/gpio.h @@ -0,0 +1,12 @@ +#ifndef _P_GPIO_H +#define _P_GPIO_H + +#include "peripherals/base.h" + +#define GPFSEL1 (PBASE+0x00200004) +#define GPSET0 (PBASE+0x0020001C) +#define GPCLR0 (PBASE+0x00200028) +#define GPPUD (PBASE+0x00200094) +#define GPPUDCLK0 (PBASE+0x00200098) + +#endif /*_P_GPIO_H */ diff --git a/exercises/lesson03/2/bl4ckout31/include/peripherals/irq.h b/exercises/lesson03/2/bl4ckout31/include/peripherals/irq.h new file mode 100644 index 00000000..731d47a6 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/peripherals/irq.h @@ -0,0 +1,27 @@ +#ifndef _P_IRQ_H +#define _P_IRQ_H + +#include "peripherals/base.h" + +#define IRQ_BASIC_PENDING (PBASE+0x0000B200) +#define IRQ_PENDING_1 (PBASE+0x0000B204) +#define IRQ_PENDING_2 (PBASE+0x0000B208) +#define FIQ_CONTROL (PBASE+0x0000B20C) +#define ENABLE_IRQS_1 (PBASE+0x0000B210) +#define ENABLE_IRQS_2 (PBASE+0x0000B214) +#define ENABLE_BASIC_IRQS (PBASE+0x0000B218) +#define DISABLE_IRQS_1 (PBASE+0x0000B21C) +#define DISABLE_IRQS_2 (PBASE+0x0000B220) +#define DISABLE_BASIC_IRQS (PBASE+0x0000B224) + +#define SYSTEM_TIMER_IRQ_0 (1 << 0) +#define SYSTEM_TIMER_IRQ_1 (1 << 1) +#define SYSTEM_TIMER_IRQ_2 (1 << 2) +#define SYSTEM_TIMER_IRQ_3 (1 << 3) + +// See BCM2537 ARM Peripherals p113 at +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf + +#define AUX_IRQ (1 << 29) + +#endif /*_P_IRQ_H */ diff --git a/exercises/lesson03/2/bl4ckout31/include/peripherals/mini_uart.h b/exercises/lesson03/2/bl4ckout31/include/peripherals/mini_uart.h new file mode 100644 index 00000000..5341dc86 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/peripherals/mini_uart.h @@ -0,0 +1,29 @@ +#ifndef _P_MINI_UART_H +#define _P_MINI_UART_H + +#include "peripherals/base.h" + +#define AUX_IRQ_REG (PBASE+0x00215000) +#define AUX_ENABLES (PBASE+0x00215004) +#define AUX_MU_IO_REG (PBASE+0x00215040) +#define AUX_MU_IER_REG (PBASE+0x00215044) +#define AUX_MU_IIR_REG (PBASE+0x00215048) +#define AUX_MU_LCR_REG (PBASE+0x0021504C) +#define AUX_MU_MCR_REG (PBASE+0x00215050) +#define AUX_MU_LSR_REG (PBASE+0x00215054) +#define AUX_MU_MSR_REG (PBASE+0x00215058) +#define AUX_MU_SCRATCH (PBASE+0x0021505C) +#define AUX_MU_CNTL_REG (PBASE+0x00215060) +#define AUX_MU_STAT_REG (PBASE+0x00215064) +#define AUX_MU_BAUD_REG (PBASE+0x00215068) + +// See BCM2537 ARM Peripherals p12 at +// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf + +#define IER_REG_EN_REC_INT (1 << 0) +#define IER_REG_INT (3 << 2) // Must be set to receive interrupts +#define IER_REG_VALUE (IER_REG_EN_REC_INT | IER_REG_INT) + +#define IIR_REG_REC_NON_EMPTY (2 << 1) + +#endif /*_P_MINI_UART_H */ diff --git a/exercises/lesson03/2/bl4ckout31/include/peripherals/timer.h b/exercises/lesson03/2/bl4ckout31/include/peripherals/timer.h new file mode 100644 index 00000000..8a52085d --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/peripherals/timer.h @@ -0,0 +1,19 @@ +#ifndef _P_TIMER_H +#define _P_TIMER_H + +#include "peripherals/base.h" + +#define TIMER_CS (PBASE+0x00003000) +#define TIMER_CLO (PBASE+0x00003004) +#define TIMER_CHI (PBASE+0x00003008) +#define TIMER_C0 (PBASE+0x0000300C) +#define TIMER_C1 (PBASE+0x00003010) +#define TIMER_C2 (PBASE+0x00003014) +#define TIMER_C3 (PBASE+0x00003018) + +#define TIMER_CS_M0 (1 << 0) +#define TIMER_CS_M1 (1 << 1) +#define TIMER_CS_M2 (1 << 2) +#define TIMER_CS_M3 (1 << 3) + +#endif /*_P_TIMER_H */ diff --git a/exercises/lesson03/2/bl4ckout31/include/printf.h b/exercises/lesson03/2/bl4ckout31/include/printf.h new file mode 100644 index 00000000..f37c1bf2 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/printf.h @@ -0,0 +1,106 @@ +/* +File: printf.h + +Copyright (C) 2004 Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +This library is realy just two files: 'printf.h' and 'printf.c'. + +They provide a simple and small (+200 loc) printf functionality to +be used in embedded systems. + +I've found them so usefull in debugging that I do not bother with a +debugger at all. + +They are distributed in source form, so to use them, just compile them +into your project. + +Two printf variants are provided: printf and sprintf. + +The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'. + +Zero padding and field width are also supported. + +If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the +long specifier is also +supported. Note that this will pull in some long math routines (pun intended!) +and thus make your executable noticably longer. + +The memory foot print of course depends on the target cpu, compiler and +compiler options, but a rough guestimate (based on a H8S target) is about +1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space. +Not too bad. Your milage may vary. By hacking the source code you can +get rid of some hunred bytes, I'm sure, but personally I feel the balance of +functionality and flexibility versus code size is close to optimal for +many embedded systems. + +To use the printf you need to supply your own character output function, +something like : + + void putc ( void* p, char c) + { + while (!SERIAL_PORT_EMPTY) ; + SERIAL_PORT_TX_REGISTER = c; + } + +Before you can call printf you need to initialize it to use your +character output function with something like: + + init_printf(NULL,putc); + +Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', +the NULL (or any pointer) you pass into the 'init_printf' will eventually be +passed to your 'putc' routine. This allows you to pass some storage space (or +anything realy) to the character output function, if necessary. +This is not often needed but it was implemented like that because it made +implementing the sprintf function so neat (look at the source code). + +The code is re-entrant, except for the 'init_printf' function, so it +is safe to call it from interupts too, although this may result in mixed output. +If you rely on re-entrancy, take care that your 'putc' function is re-entrant! + +The printf and sprintf functions are actually macros that translate to +'tfp_printf' and 'tfp_sprintf'. This makes it possible +to use them along with 'stdio.h' printf's in a single source file. +You just need to undef the names before you include the 'stdio.h'. +Note that these are not function like macros, so if you have variables +or struct members with these names, things will explode in your face. +Without variadic macros this is the best we can do to wrap these +fucnction. If it is a problem just give up the macros and use the +functions directly or rename them. + +For further details see source code. + +regs Kusti, 23.10.2004 +*/ + + +#ifndef __TFP_PRINTF__ +#define __TFP_PRINTF__ + +#include + +void init_printf(void* putp,void (*putf) (void*,char)); + +void tfp_printf(char *fmt, ...); +void tfp_sprintf(char* s,char *fmt, ...); + +void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va); + +#define printf tfp_printf +#define sprintf tfp_sprintf + +#endif diff --git a/exercises/lesson03/2/bl4ckout31/include/timer.h b/exercises/lesson03/2/bl4ckout31/include/timer.h new file mode 100644 index 00000000..eb9ef6bd --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/timer.h @@ -0,0 +1,7 @@ +#ifndef _TIMER_H +#define _TIMER_H + +void timer_init ( void ); +void handle_timer_irq ( void ); + +#endif /*_TIMER_H */ diff --git a/exercises/lesson03/2/bl4ckout31/include/utils.h b/exercises/lesson03/2/bl4ckout31/include/utils.h new file mode 100644 index 00000000..20fb61f2 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/include/utils.h @@ -0,0 +1,9 @@ +#ifndef _UTILS_H +#define _UTILS_H + +extern void delay ( unsigned long); +extern void put32 ( unsigned long, unsigned int ); +extern unsigned int get32 ( unsigned long ); +extern int get_el ( void ); + +#endif /*_UTILS_H */ diff --git a/exercises/lesson03/2/bl4ckout31/src/boot.S b/exercises/lesson03/2/bl4ckout31/src/boot.S new file mode 100644 index 00000000..6db1006e --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/src/boot.S @@ -0,0 +1,43 @@ +#include "arm/sysregs.h" + +#include "mm.h" + +.section ".text.boot" + +.globl _start +_start: + mrs x0, mpidr_el1 + and x0, x0,#0xFF // Check processor id + cbz x0, master // Hang for all non-primary CPU + b proc_hang + +proc_hang: + b proc_hang + +master: + ldr x0, =SCTLR_VALUE_MMU_DISABLED + msr sctlr_el1, x0 + + ldr x0, =HCR_VALUE + msr hcr_el2, x0 + + ldr x0, =SCR_VALUE + msr scr_el3, x0 + + ldr x0, =SPSR_VALUE + msr spsr_el3, x0 + + adr x0, el1_entry + msr elr_el3, x0 + + eret + +el1_entry: + adr x0, bss_begin + adr x1, bss_end + sub x1, x1, x0 + bl memzero + + mov sp, #LOW_MEMORY + bl kernel_main + b proc_hang // should never come here diff --git a/exercises/lesson03/2/bl4ckout31/src/config.txt b/exercises/lesson03/2/bl4ckout31/src/config.txt new file mode 100644 index 00000000..27934969 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/src/config.txt @@ -0,0 +1,2 @@ +kernel_old=1 +disable_commandline_tags=1 diff --git a/exercises/lesson03/2/bl4ckout31/src/entry.S b/exercises/lesson03/2/bl4ckout31/src/entry.S new file mode 100644 index 00000000..18a5e0c3 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/src/entry.S @@ -0,0 +1,136 @@ +#include "entry.h" + + .macro handle_invalid_entry type + kernel_entry + mov x0, #\type + mrs x1, esr_el1 + mrs x2, elr_el1 + bl show_invalid_entry_message + b err_hang + .endm + + .macro ventry label + .align 7 + b \label + .endm + + .macro kernel_entry + sub sp, sp, #S_FRAME_SIZE + stp x0, x1, [sp, #16 * 0] + stp x2, x3, [sp, #16 * 1] + stp x4, x5, [sp, #16 * 2] + stp x6, x7, [sp, #16 * 3] + stp x8, x9, [sp, #16 * 4] + stp x10, x11, [sp, #16 * 5] + stp x12, x13, [sp, #16 * 6] + stp x14, x15, [sp, #16 * 7] + stp x16, x17, [sp, #16 * 8] + stp x18, x19, [sp, #16 * 9] + stp x20, x21, [sp, #16 * 10] + stp x22, x23, [sp, #16 * 11] + stp x24, x25, [sp, #16 * 12] + stp x26, x27, [sp, #16 * 13] + stp x28, x29, [sp, #16 * 14] + str x30, [sp, #16 * 15] + .endm + + .macro kernel_exit + ldp x0, x1, [sp, #16 * 0] + ldp x2, x3, [sp, #16 * 1] + ldp x4, x5, [sp, #16 * 2] + ldp x6, x7, [sp, #16 * 3] + ldp x8, x9, [sp, #16 * 4] + ldp x10, x11, [sp, #16 * 5] + ldp x12, x13, [sp, #16 * 6] + ldp x14, x15, [sp, #16 * 7] + ldp x16, x17, [sp, #16 * 8] + ldp x18, x19, [sp, #16 * 9] + ldp x20, x21, [sp, #16 * 10] + ldp x22, x23, [sp, #16 * 11] + ldp x24, x25, [sp, #16 * 12] + ldp x26, x27, [sp, #16 * 13] + ldp x28, x29, [sp, #16 * 14] + ldr x30, [sp, #16 * 15] + add sp, sp, #S_FRAME_SIZE + eret + .endm + + +/* + * Exception vectors. + */ +.align 11 +.globl vectors +vectors: + ventry sync_invalid_el1t // Synchronous EL1t + ventry irq_invalid_el1t // IRQ EL1t + ventry fiq_invalid_el1t // FIQ EL1t + ventry error_invalid_el1t // Error EL1t + + ventry sync_invalid_el1h // Synchronous EL1h + ventry el1_irq // IRQ EL1h + ventry fiq_invalid_el1h // FIQ EL1h + ventry error_invalid_el1h // Error EL1h + + ventry sync_invalid_el0_64 // Synchronous 64-bit EL0 + ventry irq_invalid_el0_64 // IRQ 64-bit EL0 + ventry fiq_invalid_el0_64 // FIQ 64-bit EL0 + ventry error_invalid_el0_64 // Error 64-bit EL0 + + ventry sync_invalid_el0_32 // Synchronous 32-bit EL0 + ventry irq_invalid_el0_32 // IRQ 32-bit EL0 + ventry fiq_invalid_el0_32 // FIQ 32-bit EL0 + ventry error_invalid_el0_32 // Error 32-bit EL0 + +sync_invalid_el1t: + handle_invalid_entry SYNC_INVALID_EL1t + +irq_invalid_el1t: + handle_invalid_entry IRQ_INVALID_EL1t + +fiq_invalid_el1t: + handle_invalid_entry FIQ_INVALID_EL1t + +error_invalid_el1t: + handle_invalid_entry ERROR_INVALID_EL1t + +sync_invalid_el1h: + handle_invalid_entry SYNC_INVALID_EL1h + +fiq_invalid_el1h: + handle_invalid_entry FIQ_INVALID_EL1h + +error_invalid_el1h: + handle_invalid_entry ERROR_INVALID_EL1h + +sync_invalid_el0_64: + handle_invalid_entry SYNC_INVALID_EL0_64 + +irq_invalid_el0_64: + handle_invalid_entry IRQ_INVALID_EL0_64 + +fiq_invalid_el0_64: + handle_invalid_entry FIQ_INVALID_EL0_64 + +error_invalid_el0_64: + handle_invalid_entry ERROR_INVALID_EL0_64 + +sync_invalid_el0_32: + handle_invalid_entry SYNC_INVALID_EL0_32 + +irq_invalid_el0_32: + handle_invalid_entry IRQ_INVALID_EL0_32 + +fiq_invalid_el0_32: + handle_invalid_entry FIQ_INVALID_EL0_32 + +error_invalid_el0_32: + handle_invalid_entry ERROR_INVALID_EL0_32 + +el1_irq: + kernel_entry + bl handle_irq + kernel_exit + +.globl err_hang +err_hang: b err_hang diff --git a/exercises/lesson03/2/bl4ckout31/src/irq.S b/exercises/lesson03/2/bl4ckout31/src/irq.S new file mode 100644 index 00000000..1c10ed2b --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/src/irq.S @@ -0,0 +1,15 @@ +.globl irq_vector_init +irq_vector_init: + adr x0, vectors // load VBAR_EL1 with virtual + msr vbar_el1, x0 // vector table address + ret + +.globl enable_irq +enable_irq: + msr daifclr, #2 + ret + +.globl disable_irq +disable_irq: + msr daifset, #2 + ret diff --git a/exercises/lesson03/2/bl4ckout31/src/irq.c b/exercises/lesson03/2/bl4ckout31/src/irq.c new file mode 100644 index 00000000..10b311ae --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/src/irq.c @@ -0,0 +1,59 @@ +#include "utils.h" +#include "printf.h" +#include "timer.h" +#include "mini_uart.h" +#include "entry.h" +#include "peripherals/irq.h" + +const char *entry_error_messages[] = { + "SYNC_INVALID_EL1t", + "IRQ_INVALID_EL1t", + "FIQ_INVALID_EL1t", + "ERROR_INVALID_EL1T", + + "SYNC_INVALID_EL1h", + "IRQ_INVALID_EL1h", + "FIQ_INVALID_EL1h", + "ERROR_INVALID_EL1h", + + "SYNC_INVALID_EL0_64", + "IRQ_INVALID_EL0_64", + "FIQ_INVALID_EL0_64", + "ERROR_INVALID_EL0_64", + + "SYNC_INVALID_EL0_32", + "IRQ_INVALID_EL0_32", + "FIQ_INVALID_EL0_32", + "ERROR_INVALID_EL0_32" +}; + +void enable_interrupt_controller() +{ + put32(ENABLE_IRQS_1, SYSTEM_TIMER_IRQ_1 | AUX_IRQ); +} + +void show_invalid_entry_message(int type, unsigned long esr, unsigned long address) +{ + printf("%s, ESR: %x, address: %x\r\n", entry_error_messages[type], esr, address); +} + +void handle_irq(void) +{ + unsigned int irq = get32(IRQ_PENDING_1); + + // loop in case multiple interrupts have been raised + while (irq) { + // each bitflag is only 1 bit so we do not + // need to test equality against themself + if (irq & SYSTEM_TIMER_IRQ_1) { + handle_timer_irq(); + irq &= ~SYSTEM_TIMER_IRQ_1; + } else if (irq & AUX_IRQ) { + handle_uart_irq(); + irq &= ~AUX_IRQ; + } else { + printf("Unknown pending irq: %x\r\n", irq); + irq = 0; + } + } +} diff --git a/exercises/lesson03/2/bl4ckout31/src/kernel.c b/exercises/lesson03/2/bl4ckout31/src/kernel.c new file mode 100644 index 00000000..d2e64375 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/src/kernel.c @@ -0,0 +1,19 @@ +#include "printf.h" +#include "timer.h" +#include "irq.h" +#include "mini_uart.h" + + +void kernel_main(void) +{ + uart_init(); + init_printf(0, putc); + irq_vector_init(); + timer_init(); + enable_interrupt_controller(); + enable_irq(); + + while (1){ + //uart_send(uart_recv()); + } +} diff --git a/exercises/lesson03/2/bl4ckout31/src/linker.ld b/exercises/lesson03/2/bl4ckout31/src/linker.ld new file mode 100644 index 00000000..16fe2acc --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/src/linker.ld @@ -0,0 +1,11 @@ +SECTIONS +{ + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + . = ALIGN(0x8); + bss_begin = .; + .bss : { *(.bss*) } + bss_end = .; +} diff --git a/exercises/lesson03/2/bl4ckout31/src/mini_uart.c b/exercises/lesson03/2/bl4ckout31/src/mini_uart.c new file mode 100644 index 00000000..8f74cfc3 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/src/mini_uart.c @@ -0,0 +1,71 @@ +#include "utils.h" +#include "peripherals/mini_uart.h" +#include "peripherals/gpio.h" + +void uart_send ( char c ) +{ + while(1) { + if(get32(AUX_MU_LSR_REG)&0x20) + break; + } + put32(AUX_MU_IO_REG,c); +} + +char uart_recv ( void ) +{ + while(1) { + if(get32(AUX_MU_LSR_REG)&0x01) + break; + } + return(get32(AUX_MU_IO_REG)&0xFF); +} + +void uart_send_string(char* str) +{ + for (int i = 0; str[i] != '\0'; i ++) { + uart_send((char)str[i]); + } +} + +void uart_init ( void ) +{ + unsigned int selector; + + selector = get32(GPFSEL1); + selector &= ~(7<<12); // clean gpio14 + selector |= 2<<12; // set alt5 for gpio14 + selector &= ~(7<<15); // clean gpio15 + selector |= 2<<15; // set alt5 for gpio15 + put32(GPFSEL1,selector); + + put32(GPPUD,0); + delay(150); + put32(GPPUDCLK0,(1<<14)|(1<<15)); + delay(150); + put32(GPPUDCLK0,0); + + put32(AUX_ENABLES,1); //Enable mini uart (this also enables access to it registers) + put32(AUX_MU_CNTL_REG,0); //Disable auto flow control and disable receiver and transmitter (for now) + put32(AUX_MU_IER_REG, IER_REG_VALUE); //Enable receive interrupts + put32(AUX_MU_LCR_REG,3); //Enable 8 bit mode + put32(AUX_MU_MCR_REG,0); //Set RTS line to be always high + put32(AUX_MU_BAUD_REG,270); //Set baud rate to 115200 + + put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver +} + + +// This function is required by printf function +void putc ( void* p, char c) +{ + uart_send(c); +} + +void handle_uart_irq( void ) +{ + // There may be more than one byte in the FIFO. + while((get32(AUX_MU_IIR_REG) & IIR_REG_REC_NON_EMPTY) == + IIR_REG_REC_NON_EMPTY) { + uart_send(uart_recv()); + } +} \ No newline at end of file diff --git a/exercises/lesson03/2/bl4ckout31/src/mm.S b/exercises/lesson03/2/bl4ckout31/src/mm.S new file mode 100644 index 00000000..1bd32ff3 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/src/mm.S @@ -0,0 +1,6 @@ +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret diff --git a/exercises/lesson03/2/bl4ckout31/src/printf.c b/exercises/lesson03/2/bl4ckout31/src/printf.c new file mode 100644 index 00000000..1383039a --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/src/printf.c @@ -0,0 +1,233 @@ +/* +File: printf.c + +Copyright (C) 2004 Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "printf.h" + +typedef void (*putcf) (void*,char); +static putcf stdout_putf; +static void* stdout_putp; + + +#ifdef PRINTF_LONG_SUPPORT + +static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf) + { + int n=0; + unsigned int d=1; + while (num/d >= base) + d*=base; + while (d!=0) { + int dgt = num / d; + num%=d; + d/=base; + if (n || dgt>0|| d==0) { + *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); + ++n; + } + } + *bf=0; + } + +static void li2a (long num, char * bf) + { + if (num<0) { + num=-num; + *bf++ = '-'; + } + uli2a(num,10,0,bf); + } + +#endif + +static void ui2a(unsigned int num, unsigned int base, int uc,char * bf) + { + int n=0; + unsigned int d=1; + while (num/d >= base) + d*=base; + while (d!=0) { + int dgt = num / d; + num%= d; + d/=base; + if (n || dgt>0 || d==0) { + *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); + ++n; + } + } + *bf=0; + } + +static void i2a (int num, char * bf) + { + if (num<0) { + num=-num; + *bf++ = '-'; + } + ui2a(num,10,0,bf); + } + +static int a2d(char ch) + { + if (ch>='0' && ch<='9') + return ch-'0'; + else if (ch>='a' && ch<='f') + return ch-'a'+10; + else if (ch>='A' && ch<='F') + return ch-'A'+10; + else return -1; + } + +static char a2i(char ch, char** src,int base,int* nump) + { + char* p= *src; + int num=0; + int digit; + while ((digit=a2d(ch))>=0) { + if (digit>base) break; + num=num*base+digit; + ch=*p++; + } + *src=p; + *nump=num; + return ch; + } + +static void putchw(void* putp,putcf putf,int n, char z, char* bf) + { + char fc=z? '0' : ' '; + char ch; + char* p=bf; + while (*p++ && n > 0) + n--; + while (n-- > 0) + putf(putp,fc); + while ((ch= *bf++)) + putf(putp,ch); + } + +void tfp_format(void* putp,putcf putf,char *fmt, va_list va) + { + char bf[12]; + + char ch; + + + while ((ch=*(fmt++))) { + if (ch!='%') + putf(putp,ch); + else { + char lz=0; +#ifdef PRINTF_LONG_SUPPORT + char lng=0; +#endif + int w=0; + ch=*(fmt++); + if (ch=='0') { + ch=*(fmt++); + lz=1; + } + if (ch>='0' && ch<='9') { + ch=a2i(ch,&fmt,10,&w); + } +#ifdef PRINTF_LONG_SUPPORT + if (ch=='l') { + ch=*(fmt++); + lng=1; + } +#endif + switch (ch) { + case 0: + goto abort; + case 'u' : { +#ifdef PRINTF_LONG_SUPPORT + if (lng) + uli2a(va_arg(va, unsigned long int),10,0,bf); + else +#endif + ui2a(va_arg(va, unsigned int),10,0,bf); + putchw(putp,putf,w,lz,bf); + break; + } + case 'd' : { +#ifdef PRINTF_LONG_SUPPORT + if (lng) + li2a(va_arg(va, unsigned long int),bf); + else +#endif + i2a(va_arg(va, int),bf); + putchw(putp,putf,w,lz,bf); + break; + } + case 'x': case 'X' : +#ifdef PRINTF_LONG_SUPPORT + if (lng) + uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf); + else +#endif + ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf); + putchw(putp,putf,w,lz,bf); + break; + case 'c' : + putf(putp,(char)(va_arg(va, int))); + break; + case 's' : + putchw(putp,putf,w,0,va_arg(va, char*)); + break; + case '%' : + putf(putp,ch); + default: + break; + } + } + } + abort:; + } + + +void init_printf(void* putp,void (*putf) (void*,char)) + { + stdout_putf=putf; + stdout_putp=putp; + } + +void tfp_printf(char *fmt, ...) + { + va_list va; + va_start(va,fmt); + tfp_format(stdout_putp,stdout_putf,fmt,va); + va_end(va); + } + +static void putcp(void* p,char c) + { + *(*((char**)p))++ = c; + } + + + +void tfp_sprintf(char* s,char *fmt, ...) + { + va_list va; + va_start(va,fmt); + tfp_format(&s,putcp,fmt,va); + putcp(&s,0); + va_end(va); + } diff --git a/exercises/lesson03/2/bl4ckout31/src/timer.c b/exercises/lesson03/2/bl4ckout31/src/timer.c new file mode 100644 index 00000000..ac01f70e --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/src/timer.c @@ -0,0 +1,21 @@ +#include "utils.h" +#include "printf.h" +#include "peripherals/timer.h" + +const unsigned int interval = 200000; +unsigned int curVal = 0; + +void timer_init ( void ) +{ + curVal = get32(TIMER_CLO); + curVal += interval; + put32(TIMER_C1, curVal); +} + +void handle_timer_irq( void ) +{ + curVal += interval; + put32(TIMER_C1, curVal); + put32(TIMER_CS, TIMER_CS_M1); + printf("Timer interrupt received\n\r"); +} diff --git a/exercises/lesson03/2/bl4ckout31/src/utils.S b/exercises/lesson03/2/bl4ckout31/src/utils.S new file mode 100644 index 00000000..44be4857 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/src/utils.S @@ -0,0 +1,21 @@ +.globl get_el +get_el: + mrs x0, CurrentEL + lsr x0, x0, #2 + ret + +.globl put32 +put32: + str w1,[x0] + ret + +.globl get32 +get32: + ldr w0,[x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret diff --git a/exercises/lesson03/2/bl4ckout31/start.sh b/exercises/lesson03/2/bl4ckout31/start.sh new file mode 100755 index 00000000..522e5563 --- /dev/null +++ b/exercises/lesson03/2/bl4ckout31/start.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +if [ $# -ne 1 ]; then + echo "usage: $0 kernel" + exit 1 +fi + +mount -L rpiboot /mnt +cp "$1" /mnt +umount /mnt diff --git a/exercises/lesson03/3/bl4ckout31/Makefile b/exercises/lesson03/3/bl4ckout31/Makefile new file mode 100644 index 00000000..4f92a490 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/Makefile @@ -0,0 +1,31 @@ +ARMGNU ?= aarch64-linux-gnu + +COPS = -Wall -nostdlib -nostartfiles -ffreestanding -Iinclude -mgeneral-regs-only +ASMOPS = -Iinclude + +BUILD_DIR = build +SRC_DIR = src + +all : kernel8.img + +clean : + rm -rf $(BUILD_DIR) *.img + +$(BUILD_DIR)/%_c.o: $(SRC_DIR)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(COPS) -MMD -c $< -o $@ + +$(BUILD_DIR)/%_s.o: $(SRC_DIR)/%.S + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ + +C_FILES = $(wildcard $(SRC_DIR)/*.c) +ASM_FILES = $(wildcard $(SRC_DIR)/*.S) +OBJ_FILES = $(C_FILES:$(SRC_DIR)/%.c=$(BUILD_DIR)/%_c.o) +OBJ_FILES += $(ASM_FILES:$(SRC_DIR)/%.S=$(BUILD_DIR)/%_s.o) + +DEP_FILES = $(OBJ_FILES:%.o=%.d) +-include $(DEP_FILES) + +kernel8.img: $(SRC_DIR)/linker.ld $(OBJ_FILES) + $(ARMGNU)-ld -T $(SRC_DIR)/linker.ld -o $(BUILD_DIR)/kernel8.elf $(OBJ_FILES) + $(ARMGNU)-objcopy $(BUILD_DIR)/kernel8.elf -O binary kernel8.img diff --git a/exercises/lesson03/3/bl4ckout31/build.bat b/exercises/lesson03/3/bl4ckout31/build.bat new file mode 100755 index 00000000..26eb1b5e --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/build.bat @@ -0,0 +1 @@ +docker run --rm -v %cd%:/app -w /app smatyukevich/raspberry-pi-os-builder make %1 diff --git a/exercises/lesson03/3/bl4ckout31/build.sh b/exercises/lesson03/3/bl4ckout31/build.sh new file mode 100755 index 00000000..56cbff29 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/build.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker run --rm -v $(pwd):/app -w /app smatyukevich/raspberry-pi-os-builder make $1 diff --git a/exercises/lesson03/3/bl4ckout31/include/arm/sysregs.h b/exercises/lesson03/3/bl4ckout31/include/arm/sysregs.h new file mode 100644 index 00000000..90853534 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/arm/sysregs.h @@ -0,0 +1,42 @@ +#ifndef _SYSREGS_H +#define _SYSREGS_H + +// *************************************** +// SCTLR_EL1, System Control Register (EL1), Page 2654 of AArch64-Reference-Manual. +// *************************************** + +#define SCTLR_RESERVED (3 << 28) | (3 << 22) | (1 << 20) | (1 << 11) +#define SCTLR_EE_LITTLE_ENDIAN (0 << 25) +#define SCTLR_EOE_LITTLE_ENDIAN (0 << 24) +#define SCTLR_I_CACHE_DISABLED (0 << 12) +#define SCTLR_D_CACHE_DISABLED (0 << 2) +#define SCTLR_MMU_DISABLED (0 << 0) +#define SCTLR_MMU_ENABLED (1 << 0) + +#define SCTLR_VALUE_MMU_DISABLED (SCTLR_RESERVED | SCTLR_EE_LITTLE_ENDIAN | SCTLR_I_CACHE_DISABLED | SCTLR_D_CACHE_DISABLED | SCTLR_MMU_DISABLED) + +// *************************************** +// HCR_EL2, Hypervisor Configuration Register (EL2), Page 2487 of AArch64-Reference-Manual. +// *************************************** + +#define HCR_RW (1 << 31) +#define HCR_VALUE HCR_RW + +// *************************************** +// SCR_EL3, Secure Configuration Register (EL3), Page 2648 of AArch64-Reference-Manual. +// *************************************** + +#define SCR_RESERVED (3 << 4) +#define SCR_RW (1 << 10) +#define SCR_NS (1 << 0) +#define SCR_VALUE (SCR_RESERVED | SCR_RW | SCR_NS) + +// *************************************** +// SPSR_EL3, Saved Program Status Register (EL3) Page 389 of AArch64-Reference-Manual. +// *************************************** + +#define SPSR_MASK_ALL (7 << 6) +#define SPSR_EL1h (5 << 0) +#define SPSR_VALUE (SPSR_MASK_ALL | SPSR_EL1h) + +#endif diff --git a/exercises/lesson03/3/bl4ckout31/include/entry.h b/exercises/lesson03/3/bl4ckout31/include/entry.h new file mode 100644 index 00000000..cb800cfe --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/entry.h @@ -0,0 +1,26 @@ +#ifndef _ENTRY_H +#define _ENTRY_H + +#define S_FRAME_SIZE 256 // size of all saved registers + +#define SYNC_INVALID_EL1t 0 +#define IRQ_INVALID_EL1t 1 +#define FIQ_INVALID_EL1t 2 +#define ERROR_INVALID_EL1t 3 + +#define SYNC_INVALID_EL1h 4 +#define IRQ_INVALID_EL1h 5 +#define FIQ_INVALID_EL1h 6 +#define ERROR_INVALID_EL1h 7 + +#define SYNC_INVALID_EL0_64 8 +#define IRQ_INVALID_EL0_64 9 +#define FIQ_INVALID_EL0_64 10 +#define ERROR_INVALID_EL0_64 11 + +#define SYNC_INVALID_EL0_32 12 +#define IRQ_INVALID_EL0_32 13 +#define FIQ_INVALID_EL0_32 14 +#define ERROR_INVALID_EL0_32 15 + +#endif diff --git a/exercises/lesson03/3/bl4ckout31/include/irq.h b/exercises/lesson03/3/bl4ckout31/include/irq.h new file mode 100644 index 00000000..0e35437b --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/irq.h @@ -0,0 +1,10 @@ +#ifndef _IRQ_H +#define _IRQ_H + +void enable_interrupt_controller( void ); + +void irq_vector_init( void ); +void enable_irq( void ); +void disable_irq( void ); + +#endif /*_IRQ_H */ diff --git a/exercises/lesson03/3/bl4ckout31/include/mini_uart.h b/exercises/lesson03/3/bl4ckout31/include/mini_uart.h new file mode 100644 index 00000000..e3bd1372 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/mini_uart.h @@ -0,0 +1,9 @@ +#ifndef _MINI_UART_H +#define _MINI_UART_H + +void uart_init ( void ); +char uart_recv ( void ); +void uart_send ( char c ); +void putc ( void* p, char c ); + +#endif /*_MINI_UART_H */ diff --git a/exercises/lesson03/3/bl4ckout31/include/mm.h b/exercises/lesson03/3/bl4ckout31/include/mm.h new file mode 100644 index 00000000..784ac4b8 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/mm.h @@ -0,0 +1,19 @@ +#ifndef _MM_H +#define _MM_H + +#define PAGE_SHIFT 12 +#define TABLE_SHIFT 9 +#define SECTION_SHIFT (PAGE_SHIFT + TABLE_SHIFT) + +#define PAGE_SIZE (1 << PAGE_SHIFT) +#define SECTION_SIZE (1 << SECTION_SHIFT) + +#define LOW_MEMORY (2 * SECTION_SIZE) + +#ifndef __ASSEMBLER__ + +void memzero(unsigned long src, unsigned long n); + +#endif + +#endif /*_MM_H */ diff --git a/exercises/lesson03/3/bl4ckout31/include/peripherals/base.h b/exercises/lesson03/3/bl4ckout31/include/peripherals/base.h new file mode 100644 index 00000000..2ef4c57b --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/peripherals/base.h @@ -0,0 +1,7 @@ +#ifndef _P_BASE_H +#define _P_BASE_H + +#define PBASE 0x3F000000 +#define LPBASE 0x40000000 + +#endif /*_P_BASE_H */ diff --git a/exercises/lesson03/3/bl4ckout31/include/peripherals/gpio.h b/exercises/lesson03/3/bl4ckout31/include/peripherals/gpio.h new file mode 100644 index 00000000..5e9af26a --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/peripherals/gpio.h @@ -0,0 +1,12 @@ +#ifndef _P_GPIO_H +#define _P_GPIO_H + +#include "peripherals/base.h" + +#define GPFSEL1 (PBASE+0x00200004) +#define GPSET0 (PBASE+0x0020001C) +#define GPCLR0 (PBASE+0x00200028) +#define GPPUD (PBASE+0x00200094) +#define GPPUDCLK0 (PBASE+0x00200098) + +#endif /*_P_GPIO_H */ diff --git a/exercises/lesson03/3/bl4ckout31/include/peripherals/irq.h b/exercises/lesson03/3/bl4ckout31/include/peripherals/irq.h new file mode 100644 index 00000000..2429a6a9 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/peripherals/irq.h @@ -0,0 +1,31 @@ +#ifndef _P_IRQ_H +#define _P_IRQ_H + +#include "peripherals/base.h" + +#define IRQ_BASIC_PENDING (PBASE+0x0000B200) +#define IRQ_PENDING_1 (PBASE+0x0000B204) +#define IRQ_PENDING_2 (PBASE+0x0000B208) +#define FIQ_CONTROL (PBASE+0x0000B20C) +#define ENABLE_IRQS_1 (PBASE+0x0000B210) +#define ENABLE_IRQS_2 (PBASE+0x0000B214) +#define ENABLE_BASIC_IRQS (PBASE+0x0000B218) +#define DISABLE_IRQS_1 (PBASE+0x0000B21C) +#define DISABLE_IRQS_2 (PBASE+0x0000B220) +#define DISABLE_BASIC_IRQS (PBASE+0x0000B224) + +#define SYSTEM_TIMER_IRQ_0 (1 << 0) +#define SYSTEM_TIMER_IRQ_1 (1 << 1) +#define SYSTEM_TIMER_IRQ_2 (1 << 2) +#define SYSTEM_TIMER_IRQ_3 (1 << 3) + +// See BCM2836 ARM-local peripherals at +// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf + +#define TIMER_INT_CTRL_0 (0x40000040) +#define INT_SOURCE_0 (LPBASE+0x60) + +#define TIMER_INT_CTRL_0_VALUE (1 << 1) +#define GENERIC_TIMER_INTERRUPT (1 << 1) + +#endif /*_P_IRQ_H */ diff --git a/exercises/lesson03/3/bl4ckout31/include/peripherals/mini_uart.h b/exercises/lesson03/3/bl4ckout31/include/peripherals/mini_uart.h new file mode 100644 index 00000000..af95a3be --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/peripherals/mini_uart.h @@ -0,0 +1,19 @@ +#ifndef _P_MINI_UART_H +#define _P_MINI_UART_H + +#include "peripherals/base.h" + +#define AUX_ENABLES (PBASE+0x00215004) +#define AUX_MU_IO_REG (PBASE+0x00215040) +#define AUX_MU_IER_REG (PBASE+0x00215044) +#define AUX_MU_IIR_REG (PBASE+0x00215048) +#define AUX_MU_LCR_REG (PBASE+0x0021504C) +#define AUX_MU_MCR_REG (PBASE+0x00215050) +#define AUX_MU_LSR_REG (PBASE+0x00215054) +#define AUX_MU_MSR_REG (PBASE+0x00215058) +#define AUX_MU_SCRATCH (PBASE+0x0021505C) +#define AUX_MU_CNTL_REG (PBASE+0x00215060) +#define AUX_MU_STAT_REG (PBASE+0x00215064) +#define AUX_MU_BAUD_REG (PBASE+0x00215068) + +#endif /*_P_MINI_UART_H */ diff --git a/exercises/lesson03/3/bl4ckout31/include/peripherals/timer.h b/exercises/lesson03/3/bl4ckout31/include/peripherals/timer.h new file mode 100644 index 00000000..8a52085d --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/peripherals/timer.h @@ -0,0 +1,19 @@ +#ifndef _P_TIMER_H +#define _P_TIMER_H + +#include "peripherals/base.h" + +#define TIMER_CS (PBASE+0x00003000) +#define TIMER_CLO (PBASE+0x00003004) +#define TIMER_CHI (PBASE+0x00003008) +#define TIMER_C0 (PBASE+0x0000300C) +#define TIMER_C1 (PBASE+0x00003010) +#define TIMER_C2 (PBASE+0x00003014) +#define TIMER_C3 (PBASE+0x00003018) + +#define TIMER_CS_M0 (1 << 0) +#define TIMER_CS_M1 (1 << 1) +#define TIMER_CS_M2 (1 << 2) +#define TIMER_CS_M3 (1 << 3) + +#endif /*_P_TIMER_H */ diff --git a/exercises/lesson03/3/bl4ckout31/include/printf.h b/exercises/lesson03/3/bl4ckout31/include/printf.h new file mode 100644 index 00000000..f37c1bf2 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/printf.h @@ -0,0 +1,106 @@ +/* +File: printf.h + +Copyright (C) 2004 Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +This library is realy just two files: 'printf.h' and 'printf.c'. + +They provide a simple and small (+200 loc) printf functionality to +be used in embedded systems. + +I've found them so usefull in debugging that I do not bother with a +debugger at all. + +They are distributed in source form, so to use them, just compile them +into your project. + +Two printf variants are provided: printf and sprintf. + +The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'. + +Zero padding and field width are also supported. + +If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the +long specifier is also +supported. Note that this will pull in some long math routines (pun intended!) +and thus make your executable noticably longer. + +The memory foot print of course depends on the target cpu, compiler and +compiler options, but a rough guestimate (based on a H8S target) is about +1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space. +Not too bad. Your milage may vary. By hacking the source code you can +get rid of some hunred bytes, I'm sure, but personally I feel the balance of +functionality and flexibility versus code size is close to optimal for +many embedded systems. + +To use the printf you need to supply your own character output function, +something like : + + void putc ( void* p, char c) + { + while (!SERIAL_PORT_EMPTY) ; + SERIAL_PORT_TX_REGISTER = c; + } + +Before you can call printf you need to initialize it to use your +character output function with something like: + + init_printf(NULL,putc); + +Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc', +the NULL (or any pointer) you pass into the 'init_printf' will eventually be +passed to your 'putc' routine. This allows you to pass some storage space (or +anything realy) to the character output function, if necessary. +This is not often needed but it was implemented like that because it made +implementing the sprintf function so neat (look at the source code). + +The code is re-entrant, except for the 'init_printf' function, so it +is safe to call it from interupts too, although this may result in mixed output. +If you rely on re-entrancy, take care that your 'putc' function is re-entrant! + +The printf and sprintf functions are actually macros that translate to +'tfp_printf' and 'tfp_sprintf'. This makes it possible +to use them along with 'stdio.h' printf's in a single source file. +You just need to undef the names before you include the 'stdio.h'. +Note that these are not function like macros, so if you have variables +or struct members with these names, things will explode in your face. +Without variadic macros this is the best we can do to wrap these +fucnction. If it is a problem just give up the macros and use the +functions directly or rename them. + +For further details see source code. + +regs Kusti, 23.10.2004 +*/ + + +#ifndef __TFP_PRINTF__ +#define __TFP_PRINTF__ + +#include + +void init_printf(void* putp,void (*putf) (void*,char)); + +void tfp_printf(char *fmt, ...); +void tfp_sprintf(char* s,char *fmt, ...); + +void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va); + +#define printf tfp_printf +#define sprintf tfp_sprintf + +#endif diff --git a/exercises/lesson03/3/bl4ckout31/include/timer.h b/exercises/lesson03/3/bl4ckout31/include/timer.h new file mode 100644 index 00000000..0e32fad8 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/timer.h @@ -0,0 +1,13 @@ +#ifndef _TIMER_H +#define _TIMER_H + +void timer_init ( void ); +void handle_timer_irq ( void ); + +void generic_timer_init ( void ); +void handle_generic_timer_irq ( void ); + +extern void gen_timer_init(); +extern void gen_timer_reset(); + +#endif /*_TIMER_H */ diff --git a/exercises/lesson03/3/bl4ckout31/include/utils.h b/exercises/lesson03/3/bl4ckout31/include/utils.h new file mode 100644 index 00000000..20fb61f2 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/include/utils.h @@ -0,0 +1,9 @@ +#ifndef _UTILS_H +#define _UTILS_H + +extern void delay ( unsigned long); +extern void put32 ( unsigned long, unsigned int ); +extern unsigned int get32 ( unsigned long ); +extern int get_el ( void ); + +#endif /*_UTILS_H */ diff --git a/exercises/lesson03/3/bl4ckout31/src/boot.S b/exercises/lesson03/3/bl4ckout31/src/boot.S new file mode 100644 index 00000000..2521a0bf --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/boot.S @@ -0,0 +1,40 @@ +#include "arm/sysregs.h" + +#include "mm.h" + +.section ".text.boot" + +.globl _start +_start: + mrs x0, mpidr_el1 + and x0, x0,#0xFF // Check processor id + cbz x0, master // Hang for all non-primary CPU + b proc_hang + +proc_hang: + b proc_hang + +master: + ldr x0, =SCTLR_VALUE_MMU_DISABLED + msr sctlr_el1, x0 + + ldr x0, =HCR_VALUE + msr hcr_el2, x0 + + ldr x0, =SPSR_VALUE + msr spsr_el2, x0 + + adr x0, el1_entry + msr elr_el2, x0 + + eret + +el1_entry: + adr x0, bss_begin + adr x1, bss_end + sub x1, x1, x0 + bl memzero + + mov sp, #LOW_MEMORY + bl kernel_main + b proc_hang // should never come here diff --git a/exercises/lesson03/3/bl4ckout31/src/config.txt b/exercises/lesson03/3/bl4ckout31/src/config.txt new file mode 100644 index 00000000..27934969 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/config.txt @@ -0,0 +1,2 @@ +kernel_old=1 +disable_commandline_tags=1 diff --git a/exercises/lesson03/3/bl4ckout31/src/entry.S b/exercises/lesson03/3/bl4ckout31/src/entry.S new file mode 100644 index 00000000..18a5e0c3 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/entry.S @@ -0,0 +1,136 @@ +#include "entry.h" + + .macro handle_invalid_entry type + kernel_entry + mov x0, #\type + mrs x1, esr_el1 + mrs x2, elr_el1 + bl show_invalid_entry_message + b err_hang + .endm + + .macro ventry label + .align 7 + b \label + .endm + + .macro kernel_entry + sub sp, sp, #S_FRAME_SIZE + stp x0, x1, [sp, #16 * 0] + stp x2, x3, [sp, #16 * 1] + stp x4, x5, [sp, #16 * 2] + stp x6, x7, [sp, #16 * 3] + stp x8, x9, [sp, #16 * 4] + stp x10, x11, [sp, #16 * 5] + stp x12, x13, [sp, #16 * 6] + stp x14, x15, [sp, #16 * 7] + stp x16, x17, [sp, #16 * 8] + stp x18, x19, [sp, #16 * 9] + stp x20, x21, [sp, #16 * 10] + stp x22, x23, [sp, #16 * 11] + stp x24, x25, [sp, #16 * 12] + stp x26, x27, [sp, #16 * 13] + stp x28, x29, [sp, #16 * 14] + str x30, [sp, #16 * 15] + .endm + + .macro kernel_exit + ldp x0, x1, [sp, #16 * 0] + ldp x2, x3, [sp, #16 * 1] + ldp x4, x5, [sp, #16 * 2] + ldp x6, x7, [sp, #16 * 3] + ldp x8, x9, [sp, #16 * 4] + ldp x10, x11, [sp, #16 * 5] + ldp x12, x13, [sp, #16 * 6] + ldp x14, x15, [sp, #16 * 7] + ldp x16, x17, [sp, #16 * 8] + ldp x18, x19, [sp, #16 * 9] + ldp x20, x21, [sp, #16 * 10] + ldp x22, x23, [sp, #16 * 11] + ldp x24, x25, [sp, #16 * 12] + ldp x26, x27, [sp, #16 * 13] + ldp x28, x29, [sp, #16 * 14] + ldr x30, [sp, #16 * 15] + add sp, sp, #S_FRAME_SIZE + eret + .endm + + +/* + * Exception vectors. + */ +.align 11 +.globl vectors +vectors: + ventry sync_invalid_el1t // Synchronous EL1t + ventry irq_invalid_el1t // IRQ EL1t + ventry fiq_invalid_el1t // FIQ EL1t + ventry error_invalid_el1t // Error EL1t + + ventry sync_invalid_el1h // Synchronous EL1h + ventry el1_irq // IRQ EL1h + ventry fiq_invalid_el1h // FIQ EL1h + ventry error_invalid_el1h // Error EL1h + + ventry sync_invalid_el0_64 // Synchronous 64-bit EL0 + ventry irq_invalid_el0_64 // IRQ 64-bit EL0 + ventry fiq_invalid_el0_64 // FIQ 64-bit EL0 + ventry error_invalid_el0_64 // Error 64-bit EL0 + + ventry sync_invalid_el0_32 // Synchronous 32-bit EL0 + ventry irq_invalid_el0_32 // IRQ 32-bit EL0 + ventry fiq_invalid_el0_32 // FIQ 32-bit EL0 + ventry error_invalid_el0_32 // Error 32-bit EL0 + +sync_invalid_el1t: + handle_invalid_entry SYNC_INVALID_EL1t + +irq_invalid_el1t: + handle_invalid_entry IRQ_INVALID_EL1t + +fiq_invalid_el1t: + handle_invalid_entry FIQ_INVALID_EL1t + +error_invalid_el1t: + handle_invalid_entry ERROR_INVALID_EL1t + +sync_invalid_el1h: + handle_invalid_entry SYNC_INVALID_EL1h + +fiq_invalid_el1h: + handle_invalid_entry FIQ_INVALID_EL1h + +error_invalid_el1h: + handle_invalid_entry ERROR_INVALID_EL1h + +sync_invalid_el0_64: + handle_invalid_entry SYNC_INVALID_EL0_64 + +irq_invalid_el0_64: + handle_invalid_entry IRQ_INVALID_EL0_64 + +fiq_invalid_el0_64: + handle_invalid_entry FIQ_INVALID_EL0_64 + +error_invalid_el0_64: + handle_invalid_entry ERROR_INVALID_EL0_64 + +sync_invalid_el0_32: + handle_invalid_entry SYNC_INVALID_EL0_32 + +irq_invalid_el0_32: + handle_invalid_entry IRQ_INVALID_EL0_32 + +fiq_invalid_el0_32: + handle_invalid_entry FIQ_INVALID_EL0_32 + +error_invalid_el0_32: + handle_invalid_entry ERROR_INVALID_EL0_32 + +el1_irq: + kernel_entry + bl handle_irq + kernel_exit + +.globl err_hang +err_hang: b err_hang diff --git a/exercises/lesson03/3/bl4ckout31/src/irq.S b/exercises/lesson03/3/bl4ckout31/src/irq.S new file mode 100644 index 00000000..1c10ed2b --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/irq.S @@ -0,0 +1,15 @@ +.globl irq_vector_init +irq_vector_init: + adr x0, vectors // load VBAR_EL1 with virtual + msr vbar_el1, x0 // vector table address + ret + +.globl enable_irq +enable_irq: + msr daifclr, #2 + ret + +.globl disable_irq +disable_irq: + msr daifset, #2 + ret diff --git a/exercises/lesson03/3/bl4ckout31/src/irq.c b/exercises/lesson03/3/bl4ckout31/src/irq.c new file mode 100644 index 00000000..1c9c98ec --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/irq.c @@ -0,0 +1,51 @@ +#include "utils.h" +#include "printf.h" +#include "timer.h" +#include "entry.h" +#include "peripherals/irq.h" + +const char *entry_error_messages[] = { + "SYNC_INVALID_EL1t", + "IRQ_INVALID_EL1t", + "FIQ_INVALID_EL1t", + "ERROR_INVALID_EL1T", + + "SYNC_INVALID_EL1h", + "IRQ_INVALID_EL1h", + "FIQ_INVALID_EL1h", + "ERROR_INVALID_EL1h", + + "SYNC_INVALID_EL0_64", + "IRQ_INVALID_EL0_64", + "FIQ_INVALID_EL0_64", + "ERROR_INVALID_EL0_64", + + "SYNC_INVALID_EL0_32", + "IRQ_INVALID_EL0_32", + "FIQ_INVALID_EL0_32", + "ERROR_INVALID_EL0_32" +}; + +void enable_interrupt_controller() +{ + // Enables Core 0 Timers interrupt control for the generic timer + put32(TIMER_INT_CTRL_0, TIMER_INT_CTRL_0_VALUE); +} + +void show_invalid_entry_message(int type, unsigned long esr, unsigned long address) +{ + printf("%s, ESR: %x, address: %x\r\n", entry_error_messages[type], esr, address); +} + +void handle_irq(void) +{ + // Each Core has its own pending local intrrupts register + unsigned int irq = get32(INT_SOURCE_0); + switch (irq) { + case (GENERIC_TIMER_INTERRUPT): + handle_generic_timer_irq(); + break; + default: + printf("Unknown pending irq: %x\r\n", irq); + } +} \ No newline at end of file diff --git a/exercises/lesson03/3/bl4ckout31/src/kernel.c b/exercises/lesson03/3/bl4ckout31/src/kernel.c new file mode 100644 index 00000000..29661f3f --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/kernel.c @@ -0,0 +1,20 @@ +#include "printf.h" +#include "timer.h" +#include "irq.h" +#include "mini_uart.h" +#include "utils.h" + + +void kernel_main(void) +{ + uart_init(); + init_printf(0, putc); + irq_vector_init(); + generic_timer_init(); + enable_interrupt_controller(); + enable_irq(); + + while (1){ + uart_send(uart_recv()); + } +} diff --git a/exercises/lesson03/3/bl4ckout31/src/linker.ld b/exercises/lesson03/3/bl4ckout31/src/linker.ld new file mode 100644 index 00000000..e23b3161 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/linker.ld @@ -0,0 +1,12 @@ +SECTIONS +{ + . = 0x80000; + .text.boot : { *(.text.boot) } + .text : { *(.text) } + .rodata : { *(.rodata) } + .data : { *(.data) } + . = ALIGN(0x8); + bss_begin = .; + .bss : { *(.bss*) } + bss_end = .; +} diff --git a/exercises/lesson03/3/bl4ckout31/src/mini_uart.c b/exercises/lesson03/3/bl4ckout31/src/mini_uart.c new file mode 100644 index 00000000..988f4782 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/mini_uart.c @@ -0,0 +1,62 @@ +#include "utils.h" +#include "peripherals/mini_uart.h" +#include "peripherals/gpio.h" + +void uart_send ( char c ) +{ + while(1) { + if(get32(AUX_MU_LSR_REG)&0x20) + break; + } + put32(AUX_MU_IO_REG,c); +} + +char uart_recv ( void ) +{ + while(1) { + if(get32(AUX_MU_LSR_REG)&0x01) + break; + } + return(get32(AUX_MU_IO_REG)&0xFF); +} + +void uart_send_string(char* str) +{ + for (int i = 0; str[i] != '\0'; i ++) { + uart_send((char)str[i]); + } +} + +void uart_init ( void ) +{ + unsigned int selector; + + selector = get32(GPFSEL1); + selector &= ~(7<<12); // clean gpio14 + selector |= 2<<12; // set alt5 for gpio14 + selector &= ~(7<<15); // clean gpio15 + selector |= 2<<15; // set alt5 for gpio15 + put32(GPFSEL1,selector); + + put32(GPPUD,0); + delay(150); + put32(GPPUDCLK0,(1<<14)|(1<<15)); + delay(150); + put32(GPPUDCLK0,0); + + put32(AUX_ENABLES,1); //Enable mini uart (this also enables access to it registers) + put32(AUX_MU_CNTL_REG,0); //Disable auto flow control and disable receiver and transmitter (for now) + put32(AUX_MU_IER_REG,0); //Disable receive and transmit interrupts + put32(AUX_MU_LCR_REG,3); //Enable 8 bit mode + put32(AUX_MU_MCR_REG,0); //Set RTS line to be always high + put32(AUX_MU_BAUD_REG,270); //Set baud rate to 115200 + + put32(AUX_MU_CNTL_REG,3); //Finally, enable transmitter and receiver +} + + +// This function is required by printf function +void putc ( void* p, char c) +{ + uart_send(c); +} diff --git a/exercises/lesson03/3/bl4ckout31/src/mm.S b/exercises/lesson03/3/bl4ckout31/src/mm.S new file mode 100644 index 00000000..1bd32ff3 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/mm.S @@ -0,0 +1,6 @@ +.globl memzero +memzero: + str xzr, [x0], #8 + subs x1, x1, #8 + b.gt memzero + ret diff --git a/exercises/lesson03/3/bl4ckout31/src/printf.c b/exercises/lesson03/3/bl4ckout31/src/printf.c new file mode 100644 index 00000000..1383039a --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/printf.c @@ -0,0 +1,233 @@ +/* +File: printf.c + +Copyright (C) 2004 Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "printf.h" + +typedef void (*putcf) (void*,char); +static putcf stdout_putf; +static void* stdout_putp; + + +#ifdef PRINTF_LONG_SUPPORT + +static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf) + { + int n=0; + unsigned int d=1; + while (num/d >= base) + d*=base; + while (d!=0) { + int dgt = num / d; + num%=d; + d/=base; + if (n || dgt>0|| d==0) { + *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); + ++n; + } + } + *bf=0; + } + +static void li2a (long num, char * bf) + { + if (num<0) { + num=-num; + *bf++ = '-'; + } + uli2a(num,10,0,bf); + } + +#endif + +static void ui2a(unsigned int num, unsigned int base, int uc,char * bf) + { + int n=0; + unsigned int d=1; + while (num/d >= base) + d*=base; + while (d!=0) { + int dgt = num / d; + num%= d; + d/=base; + if (n || dgt>0 || d==0) { + *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); + ++n; + } + } + *bf=0; + } + +static void i2a (int num, char * bf) + { + if (num<0) { + num=-num; + *bf++ = '-'; + } + ui2a(num,10,0,bf); + } + +static int a2d(char ch) + { + if (ch>='0' && ch<='9') + return ch-'0'; + else if (ch>='a' && ch<='f') + return ch-'a'+10; + else if (ch>='A' && ch<='F') + return ch-'A'+10; + else return -1; + } + +static char a2i(char ch, char** src,int base,int* nump) + { + char* p= *src; + int num=0; + int digit; + while ((digit=a2d(ch))>=0) { + if (digit>base) break; + num=num*base+digit; + ch=*p++; + } + *src=p; + *nump=num; + return ch; + } + +static void putchw(void* putp,putcf putf,int n, char z, char* bf) + { + char fc=z? '0' : ' '; + char ch; + char* p=bf; + while (*p++ && n > 0) + n--; + while (n-- > 0) + putf(putp,fc); + while ((ch= *bf++)) + putf(putp,ch); + } + +void tfp_format(void* putp,putcf putf,char *fmt, va_list va) + { + char bf[12]; + + char ch; + + + while ((ch=*(fmt++))) { + if (ch!='%') + putf(putp,ch); + else { + char lz=0; +#ifdef PRINTF_LONG_SUPPORT + char lng=0; +#endif + int w=0; + ch=*(fmt++); + if (ch=='0') { + ch=*(fmt++); + lz=1; + } + if (ch>='0' && ch<='9') { + ch=a2i(ch,&fmt,10,&w); + } +#ifdef PRINTF_LONG_SUPPORT + if (ch=='l') { + ch=*(fmt++); + lng=1; + } +#endif + switch (ch) { + case 0: + goto abort; + case 'u' : { +#ifdef PRINTF_LONG_SUPPORT + if (lng) + uli2a(va_arg(va, unsigned long int),10,0,bf); + else +#endif + ui2a(va_arg(va, unsigned int),10,0,bf); + putchw(putp,putf,w,lz,bf); + break; + } + case 'd' : { +#ifdef PRINTF_LONG_SUPPORT + if (lng) + li2a(va_arg(va, unsigned long int),bf); + else +#endif + i2a(va_arg(va, int),bf); + putchw(putp,putf,w,lz,bf); + break; + } + case 'x': case 'X' : +#ifdef PRINTF_LONG_SUPPORT + if (lng) + uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf); + else +#endif + ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf); + putchw(putp,putf,w,lz,bf); + break; + case 'c' : + putf(putp,(char)(va_arg(va, int))); + break; + case 's' : + putchw(putp,putf,w,0,va_arg(va, char*)); + break; + case '%' : + putf(putp,ch); + default: + break; + } + } + } + abort:; + } + + +void init_printf(void* putp,void (*putf) (void*,char)) + { + stdout_putf=putf; + stdout_putp=putp; + } + +void tfp_printf(char *fmt, ...) + { + va_list va; + va_start(va,fmt); + tfp_format(stdout_putp,stdout_putf,fmt,va); + va_end(va); + } + +static void putcp(void* p,char c) + { + *(*((char**)p))++ = c; + } + + + +void tfp_sprintf(char* s,char *fmt, ...) + { + va_list va; + va_start(va,fmt); + tfp_format(&s,putcp,fmt,va); + putcp(&s,0); + va_end(va); + } diff --git a/exercises/lesson03/3/bl4ckout31/src/timer.S b/exercises/lesson03/3/bl4ckout31/src/timer.S new file mode 100644 index 00000000..1f334231 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/timer.S @@ -0,0 +1,20 @@ +/** Here, the physical timer at EL1 is used with the TimerValue views. + * Once the count-down has reach 0, the interrupt line is HIGH until + * a new timer value > 0 is write into the CNTP_TVAL_EL0 system register. + * + * See AArch64-referenc-manual p.2326 at + * https://developer.arm.com/docs/ddi0487/ca/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile + */ + +.globl gen_timer_init +gen_timer_init: + mov x0, #1 + msr CNTP_CTL_EL0, x0 + ret + +.globl gen_timer_reset +gen_timer_reset: + mov x0, #1 + lsl x0, x0, #24 + msr CNTP_TVAL_EL0, x0 + ret \ No newline at end of file diff --git a/exercises/lesson03/3/bl4ckout31/src/timer.c b/exercises/lesson03/3/bl4ckout31/src/timer.c new file mode 100644 index 00000000..b82f87c4 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/timer.c @@ -0,0 +1,34 @@ +#include "utils.h" +#include "printf.h" +#include "peripherals/timer.h" +#include "timer.h" + +const unsigned int interval = 9600000; +unsigned int curVal = 0; + +void timer_init ( void ) +{ + curVal = get32(TIMER_CLO); + curVal += interval; + put32(TIMER_C1, curVal); +} + +void handle_timer_irq( void ) +{ + curVal += interval; + put32(TIMER_C1, curVal); + put32(TIMER_CS, TIMER_CS_M1); + printf("Timer interrupt received\n\r"); +} + +void generic_timer_init ( void ) +{ + gen_timer_init(); + gen_timer_reset(); +} + +void handle_generic_timer_irq( void ) +{ + printf("Timer interrupt received\n\r"); + gen_timer_reset(); +} \ No newline at end of file diff --git a/exercises/lesson03/3/bl4ckout31/src/utils.S b/exercises/lesson03/3/bl4ckout31/src/utils.S new file mode 100644 index 00000000..1838f1af --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/src/utils.S @@ -0,0 +1,21 @@ +.globl get_el +get_el: + mrs x0, CurrentEL + lsr x0, x0, #2 + ret + +.globl put32 +put32: + str w1,[x0] + ret + +.globl get32 +get32: + ldr w0,[x0] + ret + +.globl delay +delay: + subs x0, x0, #1 + bne delay + ret \ No newline at end of file diff --git a/exercises/lesson03/3/bl4ckout31/start.sh b/exercises/lesson03/3/bl4ckout31/start.sh new file mode 100755 index 00000000..64b2e174 --- /dev/null +++ b/exercises/lesson03/3/bl4ckout31/start.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +echo "###" +echo "### Use C-a h for help" +echo "###" +echo "" + +qemu-system-aarch64 -machine raspi3 -serial null -serial mon:stdio -nographic -kernel kernel8.img