Skip to content

Commit

Permalink
Lesson 02 - Exercise 02
Browse files Browse the repository at this point in the history
  • Loading branch information
szediwy committed Jan 27, 2021
1 parent 7d5c787 commit aa0fb81
Show file tree
Hide file tree
Showing 11 changed files with 323 additions and 1 deletion.
26 changes: 26 additions & 0 deletions exercises/lesson02/2/szediwy/include/entry.h
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions exercises/lesson02/2/szediwy/include/irq.h
Original file line number Diff line number Diff line change
@@ -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 */
10 changes: 10 additions & 0 deletions exercises/lesson02/2/szediwy/include/peripherals/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,14 @@
// 0x7E000000 (legacy) -> 0x4_7E00_0000 (35-bit) -> 0x0_FE00_0000 (low peripheral)
#define PBASE 0xFE000000

// The base address of the GIC-400 is 0x4c0040000. Note that, unlike other peripheral addresses in this document, this is an
// ARM-only address and not a legacy master address. If Low Peripheral mode is enabled this base address becomes
// 0xff840000.
// The GIC-400 is configured with "NUM_CPUS=4" and "NUM_SPIS=192". For full register details, please refer to the ARM
// GIC-400 documentation on the ARM Developer website.
#define GIC_BASE 0xFF840000

// The ARMC register base address is 0x7e00b000 -> 0x4_7E00B000 -> 0x0FE00B000
#define ARMC_BASE 0x0FE00B000

#endif /*_P_BASE_H */
23 changes: 23 additions & 0 deletions exercises/lesson02/2/szediwy/include/peripherals/irq.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef _P_IRQ_H
#define _P_IRQ_H

#include "peripherals/base.h"

#define IRQ_PENDING_0_CORE_0 (PBASE+0x0000B200)
#define IRQ_PENDING_1_CORE_0 (PBASE+0x0000B204)
#define IRQ_PENDING_2_CORE_0 (PBASE+0x0000B208)
//#define FIQ_CONTROL (PBASE+0x0000B20C)
#define ENABLE_IRQS_0_CORE_0 (PBASE+0x0000B210)
#define ENABLE_IRQS_1_CORE_0 (PBASE+0x0000B214)
#define ENABLE_IRQS_2_CORE_0 (PBASE+0x0000B218)

#define DISABLE_IRQS_0_CORE_0 (PBASE+0x0000B220)
#define DISABLE_IRQS_1_CORE_0 (PBASE+0x0000B224)
#define DISABLE_IRQS_2_CORE_0 (PBASE+0x0000B228)

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

#endif /*_P_IRQ_H */
19 changes: 19 additions & 0 deletions exercises/lesson02/2/szediwy/include/peripherals/timer.h
Original file line number Diff line number Diff line change
@@ -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 */
7 changes: 7 additions & 0 deletions exercises/lesson02/2/szediwy/include/timer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef _TIMER_H
#define _TIMER_H

void timer_init ( void );
void handle_timer_irq ( void );

#endif /*_TIMER_H */
136 changes: 136 additions & 0 deletions exercises/lesson02/2/szediwy/src/entry.S
Original file line number Diff line number Diff line change
@@ -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
15 changes: 15 additions & 0 deletions exercises/lesson02/2/szediwy/src/irq.S
Original file line number Diff line number Diff line change
@@ -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
49 changes: 49 additions & 0 deletions exercises/lesson02/2/szediwy/src/irq.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#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()
{
put32(ENABLE_IRQS_0_CORE_0, SYSTEM_TIMER_IRQ_1);
}

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_0_CORE_0);
switch (irq) {
case (SYSTEM_TIMER_IRQ_1):
handle_timer_irq();
break;
default:
printf("Unknown pending irq: %x\r\n", irq);
}
}
8 changes: 7 additions & 1 deletion exercises/lesson02/2/szediwy/src/kernel.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "custom_printf.h"
#include "timer.h"
#include "utils.h"
#include "mini_uart.h"
#include "irq.h"

void kernel_main(unsigned long processor_index)
{
Expand All @@ -9,7 +11,11 @@ void kernel_main(unsigned long processor_index)
if (processor_index == 0)
{
uart_init();
init_printf(0, putc);
init_printf(0, putc);
irq_vector_init();
timer_init();
enable_interrupt_controller();
enable_irq();
}

while (processor_index != current_processor_index)
Expand Down
21 changes: 21 additions & 0 deletions exercises/lesson02/2/szediwy/src/timer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#include "utils.h"
#include "custom_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");
}

0 comments on commit aa0fb81

Please sign in to comment.