├── Makefile ├── README.md ├── aarch64.c ├── aarch64.h ├── board.h ├── boot.S ├── exception.c ├── exception.h ├── gen_tags.sh ├── gic_v3.c ├── gic_v3.h ├── kernel.c ├── linker.ld ├── psw.c ├── psw.h ├── timer.c ├── timer.h ├── uart.c ├── uart.h └── vector.S /Makefile: -------------------------------------------------------------------------------- 1 | # Test commands. 2 | # make run 3 | # Ctrl-A X (Exit) 4 | 5 | 6 | IMAGE := kernel.elf 7 | 8 | CROSS = aarch64-linux-gnu 9 | CC = ${CROSS}-gcc 10 | AS = ${CROSS}-as 11 | LD = ${CROSS}-ld 12 | OBJDUMP = ${CROSS}-objdump 13 | CFLAGS = -mcpu=cortex-a57 -Wall -Wextra -g 14 | # -mcpu=name 15 | # Specify the name of the target processor 16 | # -Wall 17 | # Turns on all optional warnings which are desirable for normal code 18 | # -Wextra 19 | # This enables some extra warning flags that are not enabled by -Wall 20 | # -g Produce debugging information in the operating system's native format. 21 | # GDB can work with this debugging information. 22 | 23 | ASM_FLAGS = -mcpu=cortex-a57 -g 24 | 25 | OBJS = boot.o vector.o exception.o kernel.o gic_v3.o uart.o psw.o aarch64.o timer.o 26 | # OBJS = boot.o gic-pl390.o kernel.o 27 | 28 | 29 | all: $(IMAGE) 30 | 31 | ${IMAGE}: linker.ld ${OBJS} 32 | ${LD} -T linker.ld $^ -o $@ 33 | ${OBJDUMP} -D kernel.elf > kernel.list 34 | 35 | #boot.o: boot.S 36 | %.o: %.S 37 | # ${AS} ${ASM_FLAGS} -c $< -o $@ 38 | $(CC) ${CFLAGS} -c $< -o $@ # for include header file in assembly 39 | 40 | %.o : %.c 41 | $(CC) ${CFLAGS} -c $< 42 | 43 | run: 44 | $(MAKE) kernel.elf 45 | # qemu-system-aarch64 -machine virt -cpu cortex-a57 -m 128 -serial stdio -nographic -nodefaults -kernel kernel.elf 46 | # qemu-system-aarch64 -machine virt,gic_version=3 -cpu cortex-a57 -nographic -kernel kernel.elf 47 | qemu-system-aarch64 -machine virt -cpu cortex-a57 -nographic -kernel kernel.elf 48 | 49 | gen_tags: 50 | ./gen_tags.sh 51 | 52 | clean_tags: 53 | rm -rf tags cscope* 54 | 55 | clean: 56 | rm -f *.o *.elf *.list 57 | 58 | .PHONY: run gen_tags clean_tags clean 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # armv8-bare-metal 2 | * Purpose 3 | * It's a bare-metal study in QEMU (-M virt -cpu cortex-a57) 4 | * How to run 5 | ``` 6 | # export PATH inclueding your cross compile tool 7 | export PATH=$PATH:/home/ryanyao/work/buildroot-2017.11-rc1/output/host/bin 8 | make run 9 | ``` 10 | * GDB (Terminal 1/2 should be in the same directory.) 11 | ``` 12 | Terminal 1: 13 | qemu-system-aarch64 -machine virt -cpu cortex-a57 -kernel kernel.elf -nographic -S -s 14 | Terminal 2: 15 | aarch64-linux-gnu-gdb kernel.elf --tui 16 | target remote :1234 17 | ``` 18 | * Timer IRQ works. It assert Timer_Handler() every 1 sec. 19 | ``` 20 | timer_test 21 | gic_v3_initialize() 22 | init_gicd() 23 | init_gicc() 24 | CurrentEL = 0x00000000 00000004 25 | RVBAR_EL1 = 0x00000000 00000000 26 | VBAR_EL1 = 0x00000000 40000000 27 | DAIF = 0x00000000 000003C0 28 | Disable the timer, CNTV_CTL_EL0 = 0x00000000 00000000 29 | System Frequency: CNTFRQ_EL0 = 0x00000000 03B9ACA0 30 | Current counter: CNTVCT_EL0 = 0x00000000 0001BA16 31 | Assert Timer IRQ after 1 sec: CNTV_CVAL_EL0 = 0x00000000 03BB66B6 32 | Enable the timer, CNTV_CTL_EL0 = 0x00000000 00000001 33 | Enable IRQ, DAIF = 0x00000000 00000340 34 | 35 | Exception Handler! (AARCH64_EXC_IRQ_SPX) 36 | IRQ found: 0x00000000 0000001B 37 | timer_handler: 38 | Disable the timer, CNTV_CTL_EL0 = 0x00000000 00000000 39 | System Frequency: CNTFRQ_EL0 = 0x00000000 03B9ACA0 40 | Current counter: CNTVCT_EL0 = 0x00000000 03BD40D5 41 | Assert Timer IRQ after 0x00000000 00000001 sec(s): CNTV_CVAL_EL0 = 0x00000000 0776ED75 42 | Enable the timer, CNTV_CTL_EL0 = 0x00000000 00000001 43 | 44 | Exception Handler! (AARCH64_EXC_IRQ_SPX) 45 | IRQ found: 0x00000000 0000001B 46 | timer_handler: 47 | Disable the timer, CNTV_CTL_EL0 = 0x00000000 00000000 48 | System Frequency: CNTFRQ_EL0 = 0x00000000 03B9ACA0 49 | Current counter: CNTVCT_EL0 = 0x00000000 0778E288 50 | Assert Timer IRQ after 0x00000000 00000001 sec(s): CNTV_CVAL_EL0 = 0x00000000 0B328F28 51 | Enable the timer, CNTV_CTL_EL0 = 0x00000000 00000001 52 | ``` 53 | 54 | # Issues 55 | * GDB can't step into main() if miss lable: main_label in boot.S (commit b72c6a8cc7033a4fed89b57f75826d201466179f) 56 | * (Fixed, 2018/07/19) Timer IRQ doesn't work(commit b72c6a8cc7033a4fed89b57f75826d201466179f) 57 | * We can see CNTV_CTL_EL0[2]:ISTATUS changes, but irq_handler doesn't be called. 58 | * And we also didn't see any changes in ISR_EL1. 59 | * Solved in commit 2aaa0bff7516e84e01acd10d8de64189839d9d51. 60 | * (Fixed, 2018/07/05) It should be some problems in vector_table_el1 in boot.S. If I set "b hang" in other vectors except lower_el_aarch64_irq, the uart outpt will be incorrect or system hang (commit b72c6a8cc7033a4fed89b57f75826d201466179f) 61 | * Root cause should be the stack memory is overlaid. Now, we set stack_top = 0x41000000 to avoid it. (commit c14d653fca24387b5996285f45f0fef2906cb2c9) 62 | 63 | 64 | # Reference 65 | * Project 66 | * [aarch64-bare-metal-qemu](https://github.com/freedomtan/aarch64-bare-metal-qemu) 67 | * [raspberrypi](https://github.com/eggman/raspberrypi) 68 | * [sample-tsk-sw](https://github.com/takeharukato/sample-tsk-sw) 69 | * QEMU 70 | * [QEMU version 2.12.50 User Documentation](https://qemu.weilnetz.de/doc/qemu-doc.html) 71 | * Makefile 72 | * [Makefile範例教學](http://maxubuntu.blogspot.com/2010/02/makefile.html) 73 | * [GNU 的連結工具 (ld, nm, objdump, ar)](http://sp1.wikidot.com/gnulinker) 74 | * [GCC Command-Line Options](http://tigcc.ticalc.org/doc/comopts.html) 75 | * [LD Index](https://sourceware.org/binutils/docs/ld/LD-Index.html#LD-Index) 76 | * ARM 77 | * [Arm® Compiler armasm User Guide](http://www.keil.com/support/man/docs/armclang_asm/armclang_asm_chunk708094578.htm) 78 | * Application Note Bare-metal Boot Code for ARMv8-A Processors Version 1.0 79 | * ARM® Architecture Reference Manual ARMv8, for ARMv8-A architecture profile Beta 80 | * ARM® Cortex®-A57 MPCore™ Processor Revision: r1p0 Technical Reference Manual 81 | * ARM® Cortex®-A Series Version: 1.0 Programmer’s Guide for ARMv8-A 82 | * ARM® Generic Interrupt Controller Architecture Specification GIC architecture version 3.0 and version 4.0 83 | -------------------------------------------------------------------------------- /aarch64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Reference: ARM® Architecture Reference Manual ARMv8, for ARMv8-A architecture profile 3 | */ 4 | #include 5 | #include "aarch64.h" 6 | 7 | /* CurrentEL, Current Exception Level 8 | EL, bits [3:2] 9 | Current exception level. Possible values of this field are: 10 | 00 EL0 11 | 01 EL1 12 | 10 EL2 13 | 11 EL3 14 | */ 15 | uint32_t raw_read_current_el(void) 16 | { 17 | uint32_t current_el; 18 | 19 | __asm__ __volatile__("mrs %0, CurrentEL\n\t" : "=r" (current_el) : : "memory"); 20 | return current_el; 21 | } 22 | 23 | uint32_t get_current_el(void) 24 | { 25 | uint32_t current_el = raw_read_current_el(); 26 | return ((current_el >> CURRENT_EL_SHIFT) & CURRENT_EL_MASK); 27 | } 28 | 29 | /* DAIF, Interrupt Mask Bits 30 | Allows access to the interrupt mask bits. 31 | 32 | D, bit [9]: Debug exceptions. 33 | A, bit [8]: SError (System Error) mask bit. 34 | I, bit [7]: IRQ mask bit. 35 | F, bit [6]: FIQ mask bit. 36 | value: 37 | 0 Exception not masked. 38 | 1 Exception masked. 39 | */ 40 | uint32_t raw_read_daif(void) 41 | { 42 | uint32_t daif; 43 | 44 | __asm__ __volatile__("mrs %0, DAIF\n\t" : "=r" (daif) : : "memory"); 45 | return daif; 46 | } 47 | 48 | void raw_write_daif(uint32_t daif) 49 | { 50 | __asm__ __volatile__("msr DAIF, %0\n\t" : : "r" (daif) : "memory"); 51 | } 52 | 53 | void enable_debug_exceptions(void) 54 | { 55 | __asm__ __volatile__("msr DAIFClr, %0\n\t" : : "i" (DAIF_DBG_BIT) : "memory"); 56 | } 57 | 58 | void enable_serror_exceptions(void) 59 | { 60 | __asm__ __volatile__("msr DAIFClr, %0\n\t" : : "i" (DAIF_ABT_BIT) : "memory"); 61 | } 62 | 63 | void enable_irq(void) 64 | { 65 | __asm__ __volatile__("msr DAIFClr, %0\n\t" : : "i" (DAIF_IRQ_BIT) : "memory"); 66 | } 67 | 68 | void enable_fiq(void) 69 | { 70 | __asm__ __volatile__("msr DAIFClr, %0\n\t" : : "i" (DAIF_FIQ_BIT) : "memory"); 71 | } 72 | 73 | void disable_debug_exceptions(void) 74 | { 75 | __asm__ __volatile__("msr DAIFSet, %0\n\t" : : "i" (DAIF_DBG_BIT) : "memory"); 76 | } 77 | 78 | void disable_serror_exceptions(void) 79 | { 80 | __asm__ __volatile__("msr DAIFSet, %0\n\t" : : "i" (DAIF_ABT_BIT) : "memory"); 81 | } 82 | 83 | void disable_irq(void) 84 | { 85 | __asm__ __volatile__("msr DAIFSet, %0\n\t" : : "i" (DAIF_IRQ_BIT) : "memory"); 86 | } 87 | 88 | void disable_fiq(void) 89 | { 90 | __asm__ __volatile__("msr DAIFSet, %0\n\t" : : "i" (DAIF_FIQ_BIT) : "memory"); 91 | } 92 | 93 | /* SPSR_EL1, Saved Program Status Register (EL1) 94 | Holds the saved processor state when an exception is taken to EL1. 95 | */ 96 | uint32_t raw_read_spsr_el1(void) 97 | { 98 | uint32_t spsr_el1; 99 | 100 | __asm__ __volatile__("mrs %0, SPSR_EL1\n\t" : "=r" (spsr_el1) : : "memory"); 101 | return spsr_el1; 102 | } 103 | 104 | void raw_write_spsr_el1(uint32_t spsr_el1) 105 | { 106 | __asm__ __volatile__("msr SPSR_EL1, %0\n\t" : : "r" (spsr_el1) : "memory"); 107 | } 108 | 109 | 110 | /* 111 | ISR_EL1, Interrupt Status Register 112 | Shows whether an IRQ, FIQ, or SError interrupt is pending. 113 | */ 114 | uint32_t raw_read_isr_el1(void) 115 | { 116 | uint32_t isr_el1; 117 | 118 | __asm__ __volatile__("mrs %0, ISR_EL1\n\t" : "=r" (isr_el1) : : "memory"); 119 | return isr_el1; 120 | } 121 | 122 | /* 123 | RVBAR_EL1, Reset Vector Base Address Register (if EL2 and EL3 not implemented) 124 | If EL1 is the highest exception level implemented, contains the 125 | IMPLEMENTATION DEFINED address that execution starts from after reset when 126 | executing in AArch64 state. 127 | */ 128 | uint64_t raw_read_rvbar_el1(void) 129 | { 130 | uint64_t rvbar_el1; 131 | 132 | __asm__ __volatile__("mrs %0, RVBAR_EL1\n\t" : "=r" (rvbar_el1) : : "memory"); 133 | return rvbar_el1; 134 | } 135 | 136 | void raw_write_rvbar_el1(uint64_t rvbar_el1) 137 | { 138 | __asm__ __volatile__("msr RVBAR_EL1, %0\n\t" : : "r" (rvbar_el1) : "memory"); 139 | } 140 | 141 | /* VBAR_EL1, Vector Base Address Register (EL1) 142 | Holds the exception base address for any exception that is taken to EL1. 143 | */ 144 | uint64_t raw_read_vbar_el1(void) 145 | { 146 | uint64_t vbar_el1; 147 | 148 | __asm__ __volatile__("mrs %0, VBAR_EL1\n\t" : "=r" (vbar_el1) : : "memory"); 149 | return vbar_el1; 150 | } 151 | 152 | void raw_write_vbar_el1(uint64_t vbar_el1) 153 | { 154 | __asm__ __volatile__("msr VBAR_EL1, %0\n\t" : : "r" (vbar_el1) : "memory"); 155 | } 156 | 157 | /* CNTV_CTL_EL0, Counter-timer Virtual Timer Control register 158 | Control register for the virtual timer. 159 | 160 | ISTATUS, bit [2]: The status of the timer interrupt. 161 | IMASK, bit [1]: Timer interrupt mask bit. 162 | ENABLE, bit [0]: Enables the timer. 163 | */ 164 | uint32_t raw_read_cntv_ctl(void) 165 | { 166 | uint32_t cntv_ctl; 167 | 168 | __asm__ __volatile__("mrs %0, CNTV_CTL_EL0\n\t" : "=r" (cntv_ctl) : : "memory"); 169 | return cntv_ctl; 170 | } 171 | 172 | void disable_cntv(void) 173 | { 174 | uint32_t cntv_ctl; 175 | 176 | cntv_ctl = raw_read_cntv_ctl(); 177 | cntv_ctl &= ~CNTV_CTL_ENABLE; 178 | __asm__ __volatile__("msr CNTV_CTL_EL0, %0\n\t" : : "r" (cntv_ctl) : "memory"); 179 | } 180 | 181 | void enable_cntv(void) 182 | { 183 | uint32_t cntv_ctl; 184 | 185 | cntv_ctl = raw_read_cntv_ctl(); 186 | cntv_ctl |= CNTV_CTL_ENABLE; 187 | __asm__ __volatile__("msr CNTV_CTL_EL0, %0\n\t" : : "r" (cntv_ctl) : "memory"); 188 | } 189 | 190 | /* 191 | CNTFRQ_EL0, Counter-timer Frequency register 192 | Holds the clock frequency of the system counter. 193 | */ 194 | uint32_t raw_read_cntfrq_el0(void) 195 | { 196 | uint32_t cntfrq_el0; 197 | 198 | __asm__ __volatile__("mrs %0, CNTFRQ_EL0\n\t" : "=r" (cntfrq_el0) : : "memory"); 199 | return cntfrq_el0; 200 | } 201 | 202 | void raw_write_cntfrq_el0(uint32_t cntfrq_el0) 203 | { 204 | __asm__ __volatile__("msr CNTFRQ_EL0, %0\n\t" : : "r" (cntfrq_el0) : "memory"); 205 | } 206 | 207 | /* CNTVCT_EL0, Counter-timer Virtual Count register 208 | Holds the 64-bit virtual count value. 209 | */ 210 | uint64_t raw_read_cntvct_el0(void) 211 | { 212 | uint64_t cntvct_el0; 213 | 214 | __asm__ __volatile__("mrs %0, CNTVCT_EL0\n\t" : "=r" (cntvct_el0) : : "memory"); 215 | return cntvct_el0; 216 | } 217 | 218 | /* CNTV_CVAL_EL0, Counter-timer Virtual Timer CompareValue register 219 | Holds the compare value for the virtual timer. 220 | */ 221 | uint64_t raw_read_cntv_cval_el0(void) 222 | { 223 | uint64_t cntv_cval_el0; 224 | 225 | __asm__ __volatile__("mrs %0, CNTV_CVAL_EL0\n\t" : "=r" (cntv_cval_el0) : : "memory"); 226 | return cntv_cval_el0; 227 | } 228 | 229 | void raw_write_cntv_cval_el0(uint64_t cntv_cval_el0) 230 | { 231 | __asm__ __volatile__("msr CNTV_CVAL_EL0, %0\n\t" : : "r" (cntv_cval_el0) : "memory"); 232 | } 233 | -------------------------------------------------------------------------------- /aarch64.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: C; coding:utf-8 -*- */ 2 | /**********************************************************************/ 3 | /* OS kernel sample */ 4 | /* Copyright 2014 Takeharu KATO */ 5 | /* */ 6 | /* AArch64 definitions */ 7 | /* */ 8 | /**********************************************************************/ 9 | #if !defined(_AARCH64_H) 10 | #define _AARCH64_H 11 | 12 | /* CurrentEL, Current Exception Level */ 13 | #define CURRENT_EL_MASK 0x3 14 | #define CURRENT_EL_SHIFT 2 15 | 16 | /* DAIF, Interrupt Mask Bits */ 17 | #define DAIF_DBG_BIT (1<<3) /* Debug mask bit */ 18 | #define DAIF_ABT_BIT (1<<2) /* Asynchronous abort mask bit */ 19 | #define DAIF_IRQ_BIT (1<<1) /* IRQ mask bit */ 20 | #define DAIF_FIQ_BIT (1<<0) /* FIQ mask bit */ 21 | 22 | /* 23 | * Interrupt flags 24 | */ 25 | #define AARCH64_DAIF_FIQ (1) /* FIQ */ 26 | #define AARCH64_DAIF_IRQ (2) /* IRQ */ 27 | 28 | /* Timer */ 29 | #define CNTV_CTL_ENABLE (1 << 0) /* Enables the timer */ 30 | #define CNTV_CTL_IMASK (1 << 1) /* Timer interrupt mask bit */ 31 | #define CNTV_CTL_ISTATUS (1 << 2) /* The status of the timer interrupt. This bit is read-only */ 32 | 33 | /* Wait For Interrupt */ 34 | #define wfi() asm volatile("wfi" : : : "memory") 35 | 36 | /* PSTATE and special purpose register access functions */ 37 | uint32_t raw_read_current_el(void); 38 | uint32_t get_current_el(void); 39 | uint32_t raw_read_daif(void); 40 | void raw_write_daif(uint32_t daif); 41 | void enable_debug_exceptions(void); 42 | void enable_serror_exceptions(void); 43 | void enable_irq(void); 44 | void enable_fiq(void); 45 | void disable_debug_exceptions(void); 46 | void disable_serror_exceptions(void); 47 | void disable_irq(void); 48 | void disable_fiq(void); 49 | /* SPSR_EL1, Saved Program Status Register (EL1) */ 50 | uint32_t raw_read_spsr_el1(void); 51 | void raw_write_spsr_el1(uint32_t spsr_el1); 52 | /* ISR_EL1, Interrupt Status Register */ 53 | uint32_t raw_read_isr_el1(void); 54 | uint64_t raw_read_rvbar_el1(void); 55 | void raw_write_rvbar_el1(uint64_t rvbar_el1); 56 | uint64_t raw_read_vbar_el1(void); 57 | void raw_write_vbar_el1(uint64_t vbar_el1); 58 | 59 | /* CNTV_CTL_EL0, Counter-timer Virtual Timer Control register */ 60 | uint32_t raw_read_cntv_ctl(void); 61 | void disable_cntv(void); 62 | void enable_cntv(void); 63 | /* CNTFRQ_EL0, Counter-timer Frequency register */ 64 | uint32_t raw_read_cntfrq_el0(void); 65 | void raw_write_cntfrq_el0(uint32_t cntfrq_el0); 66 | /* CNTVCT_EL0, Counter-timer Virtual Count register */ 67 | uint64_t raw_read_cntvct_el0(void); 68 | /* CNTV_CVAL_EL0, Counter-timer Virtual Timer CompareValue register */ 69 | uint64_t raw_read_cntv_cval_el0(void); 70 | void raw_write_cntv_cval_el0(uint64_t cntv_cval_el0); 71 | 72 | #endif /* _AARCH64_H */ 73 | -------------------------------------------------------------------------------- /board.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; coding:utf-8 -*- */ 2 | /**********************************************************************/ 3 | /* OS kernel sample */ 4 | /* Copyright 2014 Takeharu KATO */ 5 | /* */ 6 | /* Board specific definitions */ 7 | /* */ 8 | /**********************************************************************/ 9 | #if !defined(_BOARD_H) 10 | #define _BOARD_H 11 | 12 | /* 13 | * GIC on QEMU Virt 14 | */ 15 | #define QEMU_VIRT_GIC_BASE (0x08000000) 16 | #define QEMU_VIRT_GIC_INT_MAX (64) 17 | #define QEMU_VIRT_GIC_PRIO_MAX (16) 18 | /* SGI: Interrupt IDs 0-15 */ 19 | /* PPI: Interrupt IDs 16-31 */ 20 | /* SPI: Interrupt IDs 32-63 */ 21 | #define QEMU_VIRT_GIC_INTNO_SGIO (0) 22 | #define QEMU_VIRT_GIC_INTNO_PPIO (16) 23 | #define QEMU_VIRT_GIC_INTNO_SPIO (32) 24 | 25 | #define GIC_BASE (QEMU_VIRT_GIC_BASE) 26 | #define GIC_INT_MAX (QEMU_VIRT_GIC_INT_MAX) 27 | #define GIC_PRIO_MAX (QEMU_VIRT_GIC_PRIO_MAX) 28 | #define GIC_INTNO_SGI0 (QEMU_VIRT_GIC_INTNO_SGIO) 29 | #define GIC_INTNO_PPI0 (QEMU_VIRT_GIC_INTNO_PPIO) 30 | #define GIC_INTNO_SPI0 (QEMU_VIRT_GIC_INTNO_SPIO) 31 | 32 | #define GIC_PRI_SHIFT (4) 33 | #define GIC_PRI_MASK (0x0f) 34 | 35 | #define TIMER_IRQ (27) /** Timer IRQ */ 36 | #endif /* _BOARD_H */ 37 | -------------------------------------------------------------------------------- /boot.S: -------------------------------------------------------------------------------- 1 | #define ASM_FILE 1 2 | 3 | 4 | .globl _start 5 | _start: 6 | /* check CPU ID = 0x0, or jump to hang */ 7 | mrs x0, mpidr_el1 8 | and x0, x0, #3 9 | cmp x0, #0 10 | bne hang 11 | 12 | /* 13 | * Reset Vector Base Address, 14 | */ 15 | reset_vector_base: 16 | /* 17 | GDB hang if access: 18 | vbar_el3, vbar_el2 19 | scr_el3, hcr_el2 20 | */ 21 | ldr x1, = vectors 22 | msr vbar_el1, x1 23 | 24 | boot_cpu: 25 | /* configure stack */ 26 | adrp x0, stack_top // Address of 4KB page at a PC-relative offset 27 | 28 | main_label: // Why we need this label let GDB step into main()? 29 | mov sp, x0 // sp = stack_top (align with 4KB page) 30 | bl main 31 | 32 | hang: 33 | wfi 34 | b hang 35 | 36 | -------------------------------------------------------------------------------- /exception.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; coding:utf-8 -*- */ 2 | /**********************************************************************/ 3 | /* OS kernel sample */ 4 | /* Copyright 2014 Takeharu KATO */ 5 | /* */ 6 | /* Exception handler */ 7 | /* */ 8 | /**********************************************************************/ 9 | 10 | #include "exception.h" 11 | #include "uart.h" 12 | #include "psw.h" 13 | #include "board.h" 14 | #include "gic_v3.h" 15 | 16 | extern void timer_handler(void); 17 | 18 | void handle_exception(exception_frame *exc) { 19 | uart_puts("An exception occur:\n"); 20 | uart_puts("exc_type: "); 21 | uart_puthex(exc->exc_type); 22 | uart_puts("\nESR: "); uart_puthex(exc->exc_esr); 23 | uart_puts(" SP: "); uart_puthex(exc->exc_sp); 24 | uart_puts(" ELR: "); uart_puthex(exc->exc_elr); 25 | uart_puts(" SPSR: "); uart_puthex(exc->exc_spsr); 26 | uart_puts("\n x0: "); uart_puthex(exc->x0); 27 | uart_puts(" x1: "); uart_puthex(exc->x1); 28 | uart_puts(" x2: "); uart_puthex(exc->x2); 29 | uart_puts(" x3: "); uart_puthex(exc->x3); 30 | uart_puts("\n x4: "); uart_puthex(exc->x4); 31 | uart_puts(" x5: "); uart_puthex(exc->x5); 32 | uart_puts(" x6: "); uart_puthex(exc->x6); 33 | uart_puts(" x7: "); uart_puthex(exc->x7); 34 | uart_puts("\n x8: "); uart_puthex(exc->x8); 35 | uart_puts(" x9: "); uart_puthex(exc->x9); 36 | uart_puts(" x10: "); uart_puthex(exc->x10); 37 | uart_puts(" x11: "); uart_puthex(exc->x11); 38 | uart_puts("\nx12: "); uart_puthex(exc->x12); 39 | uart_puts(" x13: "); uart_puthex(exc->x13); 40 | uart_puts(" x14: "); uart_puthex(exc->x14); 41 | uart_puts(" x15: "); uart_puthex(exc->x15); 42 | uart_puts("\nx16: "); uart_puthex(exc->x16); 43 | uart_puts(" x17: "); uart_puthex(exc->x17); 44 | uart_puts(" x18: "); uart_puthex(exc->x18); 45 | uart_puts(" x19: "); uart_puthex(exc->x19); 46 | uart_puts("\nx20: "); uart_puthex(exc->x20); 47 | uart_puts(" x21: "); uart_puthex(exc->x21); 48 | uart_puts(" x22: "); uart_puthex(exc->x22); 49 | uart_puts(" x23: "); uart_puthex(exc->x23); 50 | uart_puts("\nx24: "); uart_puthex(exc->x24); 51 | uart_puts(" x25: "); uart_puthex(exc->x25); 52 | uart_puts(" x26: "); uart_puthex(exc->x26); 53 | uart_puts(" x27: "); uart_puthex(exc->x27); 54 | uart_puts("\nx28: "); uart_puthex(exc->x28); 55 | uart_puts(" x29: "); uart_puthex(exc->x29); 56 | uart_puts(" x30: "); uart_puthex(exc->x30); 57 | } 58 | 59 | void irq_handle(exception_frame *exc) 60 | { 61 | psw_t psw; 62 | irq_no irq; 63 | int rc; 64 | 65 | psw_disable_and_save_interrupt(&psw); 66 | rc = gic_v3_find_pending_irq(exc, &irq); 67 | if ( rc != IRQ_FOUND ) { 68 | uart_puts("IRQ not found!\n"); 69 | goto restore_irq_out; 70 | }else{ 71 | uart_puts("IRQ found: "); 72 | uart_puthex(irq); 73 | uart_puts("\n"); 74 | } 75 | gicd_disable_int(irq); /* Mask this irq */ 76 | gic_v3_eoi(irq); /* Send EOI for this irq line */ 77 | timer_handler(); 78 | gicd_enable_int(irq); /* unmask this irq line */ 79 | 80 | restore_irq_out: 81 | psw_restore_interrupt(&psw); 82 | } 83 | 84 | void common_trap_handler(exception_frame *exc) 85 | { 86 | uart_puts("\nException Handler! ("); 87 | //handle_exception(exc); 88 | 89 | if ( ( exc->exc_type & 0xff ) == AARCH64_EXC_SYNC_SPX ) { 90 | uart_puts("AARCH64_EXC_SYNC_SPX)\n"); 91 | handle_exception(exc); 92 | /* 93 | ti_update_preempt_count(ti, THR_EXCCNT_SHIFT, 1); 94 | psw_enable_interrupt(); 95 | hal_handle_exception(exc); 96 | psw_disable_interrupt(); 97 | ti_update_preempt_count(ti, THR_EXCCNT_SHIFT, -1); 98 | */ 99 | } 100 | 101 | if ( ( exc->exc_type & 0xff ) == AARCH64_EXC_IRQ_SPX) { 102 | uart_puts("AARCH64_EXC_IRQ_SPX)\n"); 103 | irq_handle(exc); 104 | } 105 | return; 106 | } 107 | 108 | -------------------------------------------------------------------------------- /exception.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: asm; coding:utf-8 -*- */ 2 | /************************************************************************/ 3 | /* OS kernel sample */ 4 | /* Copyright 2014 Takeharu KATO */ 5 | /* */ 6 | /************************************************************************/ 7 | 8 | #if !defined(_EXCEPTION_H) 9 | #define _EXCEPTION_H 10 | 11 | /* Vector Table 12 | * see 5.1.1 Setting up a vector table in 13 | * Application Note Bare-metal Boot Code for ARMv8-A Processors Version 1.0 14 | */ 15 | 16 | /* 17 | * AArch64 exception types 18 | */ 19 | /* Current EL with SP0 */ 20 | #define AARCH64_EXC_SYNC_SP0 (0x1) /* Synchronous */ 21 | #define AARCH64_EXC_IRQ_SP0 (0x2) /* IRQ/vIRQ */ 22 | #define AARCH64_EXC_FIQ_SP0 (0x3) /* FIQ/vFIQ */ 23 | #define AARCH64_EXC_SERR_SP0 (0x4) /* SError/vSError */ 24 | /* Current EL with SPx */ 25 | #define AARCH64_EXC_SYNC_SPX (0x11) 26 | #define AARCH64_EXC_IRQ_SPX (0x12) 27 | #define AARCH64_EXC_FIQ_SPX (0x13) 28 | #define AARCH64_EXC_SERR_SPX (0x14) 29 | /* Lower EL using AArch64 */ 30 | #define AARCH64_EXC_SYNC_AARCH64 (0x21) 31 | #define AARCH64_EXC_IRQ_AARCH64 (0x22) 32 | #define AARCH64_EXC_FIQ_AARCH64 (0x23) 33 | #define AARCH64_EXC_SERR_AARCH64 (0x24) 34 | /* Lower EL using AArch32 */ 35 | #define AARCH64_EXC_SYNC_AARCH32 (0x31) 36 | #define AARCH64_EXC_IRQ_AARCH32 (0x32) 37 | #define AARCH64_EXC_FIQ_AARCH32 (0x33) 38 | #define AARCH64_EXC_SERR_AARCH32 (0x34) 39 | 40 | #if defined(ASM_FILE) 41 | #define vector_table_align .align 11 /* Vector tables must be placed at a 2KB-aligned address */ 42 | #define vector_entry_align .align 7 /* Each entry is 128B in size*/ 43 | #define text_align .align 2 /* Text alignment */ 44 | #endif /* ASM_FILE */ 45 | 46 | 47 | /* 48 | * exception_frame offset definitions 49 | */ 50 | #define EXC_FRAME_SIZE (288) /* sizeof(struct _exception_frame) */ 51 | #define EXC_EXC_TYPE_OFFSET (0) /* __asm_offsetof(struct _exception_frame, exc_type) */ 52 | #define EXC_EXC_ESR_OFFSET (8) /* __asm_offsetof(struct _exception_frame, exc_esr) */ 53 | #define EXC_EXC_SP_OFFSET (16) /* __asm_offsetof(struct _exception_frame, exc_sp) */ 54 | #define EXC_EXC_ELR_OFFSET (24) /* __asm_offsetof(struct _exception_frame, exc_elr) */ 55 | #define EXC_EXC_SPSR_OFFSET (32)/* __asm_offsetof(struct _exception_frame, exc_spsr) */ 56 | 57 | /* 58 | * IRQ 59 | */ 60 | #define IRQ_FOUND (0) 61 | #define IRQ_NOT_FOUND (1) 62 | 63 | #if !defined(ASM_FILE) 64 | #include 65 | typedef struct _exception_frame{ 66 | uint64_t exc_type; 67 | uint64_t exc_esr; 68 | uint64_t exc_sp; 69 | uint64_t exc_elr; 70 | uint64_t exc_spsr; 71 | uint64_t x0; 72 | uint64_t x1; 73 | uint64_t x2; 74 | uint64_t x3; 75 | uint64_t x4; 76 | uint64_t x5; 77 | uint64_t x6; 78 | uint64_t x7; 79 | uint64_t x8; 80 | uint64_t x9; 81 | uint64_t x10; 82 | uint64_t x11; 83 | uint64_t x12; 84 | uint64_t x13; 85 | uint64_t x14; 86 | uint64_t x15; 87 | uint64_t x16; 88 | uint64_t x17; 89 | uint64_t x18; 90 | uint64_t x19; 91 | uint64_t x20; 92 | uint64_t x21; 93 | uint64_t x22; 94 | uint64_t x23; 95 | uint64_t x24; 96 | uint64_t x25; 97 | uint64_t x26; 98 | uint64_t x27; 99 | uint64_t x28; 100 | uint64_t x29; 101 | uint64_t x30; 102 | }exception_frame; 103 | 104 | void common_trap_handler(exception_frame *_exc); 105 | #endif /* !ASM_FILE */ 106 | #endif /* _EXCEPTION_H */ 107 | -------------------------------------------------------------------------------- /gen_tags.sh: -------------------------------------------------------------------------------- 1 | find ./ -name "*.[chsS]" -print >> cscope.files 2 | cscope -bkq -i cscope.files 3 | ctags -R 4 | -------------------------------------------------------------------------------- /gic_v3.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; coding:utf-8 -*- */ 2 | /**********************************************************************/ 3 | /* OS kernel sample */ 4 | /* Copyright 2014 Takeharu KATO */ 5 | /* */ 6 | /* Arm Generic Interrupt Controller(PL390) */ 7 | /* */ 8 | /**********************************************************************/ 9 | 10 | /**********************************************************************/ 11 | /* armv8-bare-metal */ 12 | /* Copyright 2018 Nienfeng Yao */ 13 | /* */ 14 | /* Reference: ARM® Generic Interrupt Controller Architecture */ 15 | /* Specification GIC architecture version 3.0 and version 4.0 */ 16 | /* */ 17 | /**********************************************************************/ 18 | #include 19 | #include "board.h" 20 | #include "exception.h" 21 | #include "gic_v3.h" 22 | #include "uart.h" 23 | 24 | 25 | /* Initialize GIC Controller */ 26 | static void init_gicc(void) 27 | { 28 | uint32_t pending_irq; 29 | 30 | uart_puts("init_gicc()\n"); 31 | /* Disable CPU interface */ 32 | *REG_GIC_GICC_CTLR = GICC_CTLR_DISABLE; 33 | 34 | /* Set the priority level as the lowest priority */ 35 | /* Note: Higher priority corresponds to a lower Priority field value in the GIC_PMR. 36 | * In addition to this, writing 255 to the GICC_PMR always sets it to the 37 | * largest supported priority field value. 38 | */ 39 | *REG_GIC_GICC_PMR = GICC_PMR_PRIO_MIN; 40 | 41 | /* Handle all of interrupts in a single group */ 42 | *REG_GIC_GICC_BPR = GICC_BPR_NO_GROUP; 43 | 44 | /* Clear all of the active interrupts */ 45 | for(pending_irq = ( *REG_GIC_GICC_IAR & GICC_IAR_INTR_IDMASK ); 46 | ( pending_irq != GICC_IAR_SPURIOUS_INTR ); 47 | pending_irq = ( *REG_GIC_GICC_IAR & GICC_IAR_INTR_IDMASK ) ) 48 | *REG_GIC_GICC_EOIR = *REG_GIC_GICC_IAR; 49 | 50 | /* Enable CPU interface */ 51 | *REG_GIC_GICC_CTLR = GICC_CTLR_ENABLE; 52 | } 53 | 54 | static void init_gicd(void) 55 | { 56 | int32_t i, regs_nr; 57 | 58 | uart_puts("init_gicd()\n"); 59 | /* Diable distributor */ 60 | *REG_GIC_GICD_CTLR = GIC_GICD_CTLR_DISABLE; 61 | 62 | /* Disable all IRQs */ 63 | regs_nr = (GIC_INT_MAX + GIC_GICD_INT_PER_REG - 1) / GIC_GICD_INT_PER_REG; 64 | for (i = 0; regs_nr > i; ++i) 65 | *REG_GIC_GICD_ICENABLER(i) = ~((uint32_t)(0)); 66 | 67 | /* Clear all pending IRQs */ 68 | regs_nr = (GIC_INT_MAX + GIC_GICD_INT_PER_REG - 1) / GIC_GICD_INT_PER_REG; 69 | for (i = 0; regs_nr > i; ++i) 70 | *REG_GIC_GICD_ICPENDR(i) = ~((uint32_t)(0)); 71 | 72 | /* Set all of interrupt priorities as the lowest priority */ 73 | regs_nr = ( GIC_INT_MAX + GIC_GICD_IPRIORITY_PER_REG - 1) / 74 | GIC_GICD_IPRIORITY_PER_REG ; 75 | for (i = 0; regs_nr > i; i++) 76 | *REG_GIC_GICD_IPRIORITYR(i) = ~((uint32_t)(0)); 77 | 78 | /* Set target of all of shared peripherals to processor 0 */ 79 | for (i = GIC_INTNO_SPI0 / GIC_GICD_ITARGETSR_PER_REG; 80 | ( (GIC_INT_MAX + (GIC_GICD_ITARGETSR_PER_REG - 1) ) / 81 | GIC_GICD_ITARGETSR_PER_REG ) > i; ++i) 82 | *REG_GIC_GICD_ITARGETSR(i) = 83 | (uint32_t)GIC_GICD_ITARGETSR_CORE0_TARGET_BMAP; 84 | 85 | /* Set trigger type for all peripheral interrupts level triggered */ 86 | for (i = GIC_INTNO_PPI0 / GIC_GICD_ICFGR_PER_REG; 87 | (GIC_INT_MAX + (GIC_GICD_ICFGR_PER_REG - 1)) / GIC_GICD_ICFGR_PER_REG > i; ++i) 88 | *REG_GIC_GICD_ICFGR(i) = GIC_GICD_ICFGR_LEVEL; 89 | 90 | /* Enable distributor */ 91 | *REG_GIC_GICD_CTLR = GIC_GICD_CTLR_ENABLE; 92 | } 93 | 94 | /** Disable IRQ 95 | @param[in] irq IRQ number 96 | */ 97 | void gicd_disable_int(irq_no irq) { 98 | *REG_GIC_GICD_ICENABLER( (irq / GIC_GICD_ICENABLER_PER_REG) ) = 99 | 1U << ( irq % GIC_GICD_ICENABLER_PER_REG ); 100 | } 101 | 102 | /** Enable IRQ 103 | @param[in] irq IRQ number 104 | */ 105 | void gicd_enable_int(irq_no irq) { 106 | 107 | *REG_GIC_GICD_ISENABLER( (irq / GIC_GICD_ISENABLER_PER_REG) ) = 108 | 1U << ( irq % GIC_GICD_ISENABLER_PER_REG ); 109 | 110 | } 111 | 112 | /** Clear a pending interrupt 113 | @param[in] irq IRQ number 114 | */ 115 | void gicd_clear_pending(irq_no irq) { 116 | 117 | *REG_GIC_GICD_ICPENDR( (irq / GIC_GICD_ICPENDR_PER_REG) ) = 118 | 1U << ( irq % GIC_GICD_ICPENDR_PER_REG ); 119 | } 120 | 121 | 122 | /** Probe pending interrupt 123 | @param[in] irq IRQ number 124 | */ 125 | static int gicd_probe_pending(irq_no irq) { 126 | int is_pending; 127 | 128 | is_pending = ( *REG_GIC_GICD_ISPENDR( (irq / GIC_GICD_ISPENDR_PER_REG) ) & 129 | ( 1U << ( irq % GIC_GICD_ISPENDR_PER_REG ) ) ); 130 | 131 | return ( is_pending != 0 ); 132 | } 133 | 134 | /** Set an interrupt target processor 135 | @param[in] irq IRQ number 136 | @param[in] p Target processor mask 137 | 0x1 processor 0 138 | 0x2 processor 1 139 | 0x4 processor 2 140 | 0x8 processor 3 141 | */ 142 | static void gicd_set_target(irq_no irq, uint32_t p){ 143 | uint32_t shift; 144 | uint32_t reg; 145 | 146 | shift = (irq % GIC_GICD_ITARGETSR_PER_REG) * GIC_GICD_ITARGETSR_SIZE_PER_REG; 147 | 148 | reg = *REG_GIC_GICD_ITARGETSR(irq / GIC_GICD_ITARGETSR_PER_REG); 149 | reg &= ~( ((uint32_t)(0xff)) << shift); 150 | reg |= (p << shift); 151 | *REG_GIC_GICD_ITARGETSR(irq / GIC_GICD_ITARGETSR_PER_REG) = reg; 152 | } 153 | 154 | /** Set an interrupt priority 155 | @param[in] irq IRQ number 156 | @param[in] prio Interrupt priority in Arm specific expression 157 | */ 158 | static void gicd_set_priority(irq_no irq, uint32_t prio){ 159 | uint32_t shift; 160 | uint32_t reg; 161 | 162 | shift = (irq % GIC_GICD_IPRIORITY_PER_REG) * GIC_GICD_IPRIORITY_SIZE_PER_REG; 163 | reg = *REG_GIC_GICD_IPRIORITYR(irq / GIC_GICD_IPRIORITY_PER_REG); 164 | reg &= ~(((uint32_t)(0xff)) << shift); 165 | reg |= (prio << shift); 166 | *REG_GIC_GICD_IPRIORITYR(irq / GIC_GICD_IPRIORITY_PER_REG) = reg; 167 | } 168 | 169 | /** Configure IRQ 170 | @param[in] irq IRQ number 171 | @param[in] config Configuration value for GICD_ICFGR 172 | */ 173 | static void gicd_config(irq_no irq, unsigned int config) 174 | { 175 | uint32_t shift; 176 | uint32_t reg; 177 | 178 | shift = (irq % GIC_GICD_ICFGR_PER_REG) * GIC_GICD_ICFGR_SIZE_PER_REG; /* GICD_ICFGR has 16 fields, each field has 2bits. */ 179 | 180 | reg = *REG_GIC_GICD_ICFGR( irq / GIC_GICD_ICFGR_PER_REG); 181 | 182 | reg &= ~( ( (uint32_t)(0x03) ) << shift ); /* Clear the field */ 183 | reg |= ( ( (uint32_t)config ) << shift ); /* Set the value to the field correponding to irq */ 184 | *REG_GIC_GICD_ICFGR( irq / GIC_GICD_ICFGR_PER_REG) = reg; 185 | } 186 | 187 | /** Send End of Interrupt to IRQ line for GIC 188 | @param[in] ctrlr IRQ controller information 189 | @param[in] irq IRQ number 190 | */ 191 | void gic_v3_eoi(irq_no irq) { 192 | gicd_clear_pending(irq); 193 | } 194 | 195 | /* Initialize GIC IRQ controller */ 196 | /* RyanYao: 2018/07/20 197 | * I supppose the current access is security, because GICD_CTLR.DS is 0b0 and 198 | * we can access. 199 | */ 200 | void gic_v3_initialize(void) 201 | { 202 | 203 | uart_puts("gic_v3_initialize()\n"); 204 | init_gicd(); 205 | init_gicc(); 206 | gicd_config(TIMER_IRQ, GIC_GICD_ICFGR_EDGE); 207 | gicd_set_priority(TIMER_IRQ, 0 << GIC_PRI_SHIFT ); /* Set priority */ 208 | gicd_set_target(TIMER_IRQ, 0x1); /* processor 0 */ 209 | gicd_clear_pending(TIMER_IRQ); 210 | gicd_enable_int(TIMER_IRQ); 211 | } 212 | 213 | 214 | /** Find pending IRQ 215 | @param[in] exc An exception frame 216 | @param[in,out] irqp An IRQ number to be processed 217 | */ 218 | int gic_v3_find_pending_irq(struct _exception_frame *exc __attribute__((unused)), irq_no *irqp) { 219 | int rc; 220 | irq_no i; 221 | for( i = 0; GIC_INT_MAX > i; ++i) { 222 | if ( gicd_probe_pending(i) ) { 223 | 224 | rc = IRQ_FOUND; 225 | *irqp = i; 226 | goto found; 227 | } 228 | } 229 | 230 | rc = IRQ_NOT_FOUND ; 231 | found: 232 | return rc; 233 | } 234 | -------------------------------------------------------------------------------- /gic_v3.h: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; coding:utf-8 -*- */ 2 | /**********************************************************************/ 3 | /* OS kernel sample */ 4 | /* Copyright 2014 Takeharu KATO */ 5 | /* */ 6 | /* PrimeCell Generic Interrupt Controller (PL390) */ 7 | /* */ 8 | /**********************************************************************/ 9 | 10 | /**********************************************************************/ 11 | /* armv8-bare-metal */ 12 | /* Copyright 2018 Nienfeng Yao */ 13 | /* */ 14 | /* Reference: ARM® Generic Interrupt Controller Architecture */ 15 | /* Specification GIC architecture version 3.0 and version 4.0 */ 16 | /* */ 17 | /**********************************************************************/ 18 | #if !defined(_GIC_V3_H) 19 | #define _GIC_V3_H 20 | 21 | #if !defined(_BOARD_H) 22 | #error "Include board.h before this header file." 23 | #endif /* !_BOARD_H */ 24 | 25 | #include "exception.h" 26 | 27 | typedef int32_t irq_no; /* IRQ no */ 28 | 29 | #define GIC_GICD_BASE (GIC_BASE) /* GICD MMIO base address */ 30 | #define GIC_GICC_BASE (GIC_BASE + 0x10000) /* GICC MMIO base address */ 31 | 32 | #define GIC_GICD_INT_PER_REG (32) /* 32 interrupts per reg */ 33 | #define GIC_GICD_IPRIORITY_PER_REG (4) /* 4 priority per reg */ 34 | #define GIC_GICD_IPRIORITY_SIZE_PER_REG (8) /* priority element size */ 35 | #define GIC_GICD_ITARGETSR_CORE0_TARGET_BMAP (0x01010101) /* CPU interface 0 */ 36 | #define GIC_GICD_ITARGETSR_PER_REG (4) 37 | #define GIC_GICD_ITARGETSR_SIZE_PER_REG (8) 38 | #define GIC_GICD_ICFGR_PER_REG (16) 39 | #define GIC_GICD_ICFGR_SIZE_PER_REG (2) 40 | #define GIC_GICD_ICENABLER_PER_REG (32) 41 | #define GIC_GICD_ISENABLER_PER_REG (32) 42 | #define GIC_GICD_ICPENDR_PER_REG (32) 43 | #define GIC_GICD_ISPENDR_PER_REG (32) 44 | 45 | /* 8.12 The GIC CPU interface register map */ 46 | #define GIC_GICC_CTLR (GIC_GICC_BASE + 0x000) /* CPU Interface Control Register */ 47 | #define GIC_GICC_PMR (GIC_GICC_BASE + 0x004) /* Interrupt Priority Mask Register */ 48 | #define GIC_GICC_BPR (GIC_GICC_BASE + 0x008) /* Binary Point Register */ 49 | #define GIC_GICC_IAR (GIC_GICC_BASE + 0x00C) /* Interrupt Acknowledge Register */ 50 | #define GIC_GICC_EOIR (GIC_GICC_BASE + 0x010) /* End of Interrupt Register */ 51 | #define GIC_GICC_RPR (GIC_GICC_BASE + 0x014) /* Running Priority Register */ 52 | #define GIC_GICC_HPIR (GIC_GICC_BASE + 0x018) /* Highest Pending Interrupt Register */ 53 | #define GIC_GICC_ABPR (GIC_GICC_BASE + 0x01C) /* Aliased Binary Point Register */ 54 | #define GIC_GICC_IIDR (GIC_GICC_BASE + 0x0FC) /* CPU Interface Identification Register */ 55 | 56 | /* 8.13.7 GICC_CTLR, CPU Interface Control Register */ 57 | #define GICC_CTLR_ENABLE (0x1) /* Enable GICC */ 58 | #define GICC_CTLR_DISABLE (0x0) /* Disable GICC */ 59 | 60 | /* 8.13.14 GICC_PMR, CPU Interface Priority Mask Register */ 61 | #define GICC_PMR_PRIO_MIN (0xff) /* The lowest level mask */ 62 | #define GICC_PMR_PRIO_HIGH (0x0) /* The highest level mask */ 63 | 64 | /* 8.13.6 GICC_BPR, CPU Interface Binary Point Register */ 65 | /* In systems that support only one Security state, when GICC_CTLR.CBPR == 0, 66 | this register determines only Group 0 interrupt preemption. */ 67 | #define GICC_BPR_NO_GROUP (0x0) /* handle all interrupts */ 68 | 69 | /* 8.13.11 GICC_IAR, CPU Interface Interrupt Acknowledge Register */ 70 | #define GICC_IAR_INTR_IDMASK (0x3ff) /* 0-9 bits means Interrupt ID */ 71 | #define GICC_IAR_SPURIOUS_INTR (0x3ff) /* 1023 means spurious interrupt */ 72 | 73 | /* 8.8 The GIC Distributor register map */ 74 | #define GIC_GICD_CTLR (GIC_GICD_BASE + 0x000) /* Distributor Control Register */ 75 | #define GIC_GICD_TYPER (GIC_GICD_BASE + 0x004) /* Interrupt Controller Type Register */ 76 | #define GIC_GICD_IIDR (GIC_GICD_BASE + 0x008) /* Distributor Implementer Identification Register */ 77 | #define GIC_GICD_IGROUPR(n) (GIC_GICD_BASE + 0x080 + ( (n) * 4 ) ) /* Interrupt Group Registers */ 78 | #define GIC_GICD_ISENABLER(n) (GIC_GICD_BASE + 0x100 + ( (n) * 4 ) ) /* Interrupt Set-Enable Registers */ 79 | #define GIC_GICD_ICENABLER(n) (GIC_GICD_BASE + 0x180 + ( (n) * 4 ) ) /* Interrupt Clear-Enable Registers */ 80 | #define GIC_GICD_ISPENDR(n) (GIC_GICD_BASE + 0x200 + ( (n) * 4 ) ) /* Interrupt Set-Pending Registers */ 81 | #define GIC_GICD_ICPENDR(n) (GIC_GICD_BASE + 0x280 + ( (n) * 4 ) ) /* Interrupt Clear-Pending Registers */ 82 | #define GIC_GICD_ISACTIVER(n) (GIC_GICD_BASE + 0x300 + ( (n) * 4 ) ) /* Interrupt Set-Active Registers */ 83 | #define GIC_GICD_ICACTIVER(n) (GIC_GICD_BASE + 0x380 + ( (n) * 4 ) ) /* Interrupt Clear-Active Registers */ 84 | #define GIC_GICD_IPRIORITYR(n) (GIC_GICD_BASE + 0x400 + ( (n) * 4 ) ) /* Interrupt Priority Registers */ 85 | #define GIC_GICD_ITARGETSR(n) (GIC_GICD_BASE + 0x800 + ( (n) * 4 ) ) /* Interrupt Processor Targets Registers */ 86 | #define GIC_GICD_ICFGR(n) (GIC_GICD_BASE + 0xc00 + ( (n) * 4 ) ) /* Interrupt Configuration Registers */ 87 | #define GIC_GICD_NSCAR(n) (GIC_GICD_BASE + 0xe00 + ( (n) * 4 ) ) /* Non-secure Access Control Registers */ 88 | #define GIC_GICD_SGIR (GIC_GICD_BASE + 0xf00 ) /* Software Generated Interrupt Register */ 89 | #define GIC_GICD_CPENDSGIR(n) (GIC_GICD_BASE + 0xf10 + ( (n) * 4 ) ) /* SGI Clear-Pending Registers */ 90 | #define GIC_GICD_SPENDSGIR(n) (GIC_GICD_BASE + 0xf20 + ( (n) * 4 ) ) /* SGI Set-Pending Registers */ 91 | 92 | /* 8.9.4 GICD_CTLR, Distributor Control Register */ 93 | #define GIC_GICD_CTLR_ENABLE (0x1) /* Enable GICD */ 94 | #define GIC_GICD_CTLR_DISABLE (0x0) /* Disable GICD */ 95 | 96 | /* 8.9.7 GICD_ICFGR, Interrupt Configuration Registers */ 97 | #define GIC_GICD_ICFGR_LEVEL (0x0) /* level-sensitive */ 98 | #define GIC_GICD_ICFGR_EDGE (0x2) /* edge-triggered */ 99 | 100 | /* Register access macros for GICC */ 101 | #define REG_GIC_GICC_CTLR ((volatile uint32_t *)(uintptr_t)GIC_GICC_CTLR) 102 | #define REG_GIC_GICC_PMR ((volatile uint32_t *)(uintptr_t)GIC_GICC_PMR) 103 | #define REG_GIC_GICC_BPR ((volatile uint32_t *)(uintptr_t)GIC_GICC_BPR) 104 | #define REG_GIC_GICC_IAR ((volatile uint32_t *)(uintptr_t)GIC_GICC_IAR) 105 | #define REG_GIC_GICC_EOIR ((volatile uint32_t *)(uintptr_t)GIC_GICC_EOIR) 106 | #define REG_GIC_GICC_RPR ((volatile uint32_t *)(uintptr_t)GIC_GICC_RPR) 107 | #define REG_GIC_GICC_HPIR ((volatile uint32_t *)(uintptr_t)GIC_GICC_HPIR) 108 | #define REG_GIC_GICC_ABPR ((volatile uint32_t *)(uintptr_t)GIC_GICC_ABPR) 109 | #define REG_GIC_GICC_IIDR ((volatile uint32_t *)(uintptr_t)GIC_GICC_IIDR) 110 | 111 | /* Register access macros for GICD */ 112 | #define REG_GIC_GICD_CTLR ((volatile uint32_t *)(uintptr_t)GIC_GICD_CTLR) 113 | #define REG_GIC_GICD_TYPE ((volatile uint32_t *)(uintptr_t)GIC_GICD_TYPE) 114 | #define REG_GIC_GICD_IIDR ((volatile uint32_t *)(uintptr_t)GIC_GICD_IIDR) 115 | #define REG_GIC_GICD_IGROUPR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_IGROUPR(n)) 116 | #define REG_GIC_GICD_ISENABLER(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ISENABLER(n)) 117 | #define REG_GIC_GICD_ICENABLER(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ICENABLER(n)) 118 | #define REG_GIC_GICD_ISPENDR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ISPENDR(n)) 119 | #define REG_GIC_GICD_ICPENDR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ICPENDR(n)) 120 | #define REG_GIC_GICD_ISACTIVER(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ISACTIVER(n)) 121 | #define REG_GIC_GICD_ICACTIVER(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ICACTIVER(n)) 122 | #define REG_GIC_GICD_IPRIORITYR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_IPRIORITYR(n)) 123 | #define REG_GIC_GICD_ITARGETSR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ITARGETSR(n)) 124 | #define REG_GIC_GICD_ICFGR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_ICFGR(n)) 125 | #define REG_GIC_GICD_NSCAR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_NSCAR(n)) 126 | #define REG_GIC_GICD_SGIR ((volatile uint32_t *)(uintptr_t)GIC_GICD_SGIR) 127 | #define REG_GIC_GICD_CPENDSGIR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_CPENDSGIR(n)) 128 | #define REG_GIC_GICD_SPENDSGIR(n) ((volatile uint32_t *)(uintptr_t)GIC_GICD_SPENDSGIR(n)) 129 | 130 | void gic_v3_initialize(void); 131 | void gic_v3_eoi(irq_no irq); 132 | int gic_v3_find_pending_irq(struct _exception_frame *exc __attribute__((unused)), irq_no *irqp); 133 | void gicd_disable_int(irq_no irq); 134 | void gicd_enable_int(irq_no irq); 135 | void gicd_clear_pending(irq_no irq); 136 | #endif /* _GIC_V3_H */ 137 | -------------------------------------------------------------------------------- /kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "board.h" 3 | #include "gic_v3.h" 4 | #include "aarch64.h" 5 | #include "uart.h" 6 | #include "timer.h" 7 | 8 | 9 | /* Exception SVC Test */ 10 | void exception_svc(void) 11 | { 12 | /* 13 | Supervisor call to allow application code to call the OS. 14 | It generates an exception targeting exception level 1 (EL1). 15 | */ 16 | asm("svc #0xdead"); 17 | } 18 | 19 | /* Main */ 20 | void exception_svc_test(void) 21 | { 22 | uart_puts("exception_svc_test... start\n"); 23 | /* SVC instruction causes a Supervisor Call exception. */ 24 | /* vector_table:_curr_el_spx_sync should be called */ 25 | exception_svc(); 26 | 27 | // Wait for Interrupt. 28 | wfi(); 29 | uart_puts("exception_svc_test... done\n"); 30 | } 31 | 32 | int main(void) { 33 | //exception_svc_test(); 34 | timer_test(); 35 | } 36 | 37 | 38 | -------------------------------------------------------------------------------- /linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | STACKTOP = 0x41000000; 4 | 5 | SECTIONS 6 | { 7 | /* Starts at LOADER_ADDR. */ 8 | . = 0x40000000; 9 | __start = .; 10 | __text_start = .; 11 | .text : 12 | { 13 | KEEP(*(.text.boot)) 14 | *(.text) 15 | } 16 | . = ALIGN(4096); /* align to page size */ 17 | __text_end = .; 18 | 19 | __data_start = .; 20 | .data : 21 | { 22 | *(.data) 23 | } 24 | . = ALIGN(4096); /* align to page size */ 25 | __data_end = .; 26 | 27 | __bss_start = .; 28 | .bss : 29 | { 30 | bss = .; 31 | *(.bss) 32 | } 33 | . = ALIGN(4096); /* align to page size */ 34 | __bss_end = .; 35 | __end = .; 36 | 37 | . = STACKTOP ; /* stack memory */ 38 | stack_top = .; 39 | } 40 | __bss_size = (__bss_end - __bss_start)>>3; 41 | -------------------------------------------------------------------------------- /psw.c: -------------------------------------------------------------------------------- 1 | /* -*- mode: c; coding:utf-8 -*- */ 2 | /**********************************************************************/ 3 | /* OS kernel sample */ 4 | /* Copyright 2014 Takeharu KATO */ 5 | /* */ 6 | /* Processor Status Word */ 7 | /* */ 8 | /**********************************************************************/ 9 | #include 10 | #include "aarch64.h" 11 | #include "psw.h" 12 | 13 | /** Disable interrupt at CPU level 14 |     @ param [in] pswp Processor status word return area before interrupt disabled 15 | */ 16 | void psw_disable_and_save_interrupt(psw_t *pswp) { 17 | psw_t psw; 18 | 19 | __save_psw(psw); 20 | psw_disable_interrupt(); 21 | *pswp = psw; 22 | } 23 | 24 | 25 | /** Restore interrupt status at CPU level 26 | @ param [in] pswp Processor status word return area 27 | */ 28 | void psw_restore_interrupt(psw_t *pswp) { 29 | psw_t psw; 30 | 31 | psw = *pswp; 32 | __restore_psw(psw); 33 | } 34 | -------------------------------------------------------------------------------- /psw.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NienfengYao/armv8-bare-metal/572c6f95880e70aa92fe9fed4b8ad7697082a764/psw.h -------------------------------------------------------------------------------- /timer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "aarch64.h" 3 | #include "board.h" 4 | #include "gic_v3.h" 5 | #include "uart.h" 6 | #include "timer.h" 7 | 8 | #define TIMER_DEBUG 0 9 | #define TIMER_WAIT 1 /* Assert Timer IRQ after n secs */ 10 | 11 | static uint32_t cntfrq; /* System frequency */ 12 | 13 | #if TIMER_DEBUG 14 | void timer_handler(void){} 15 | #else 16 | /* Assert Timer IRQ after n secs */ 17 | void timer_handler(void) 18 | { 19 | uint64_t ticks, current_cnt; 20 | uint32_t val; 21 | 22 | uart_puts("timer_handler: \n"); 23 | 24 | // Disable the timer 25 | disable_cntv(); 26 | uart_puts("\tDisable the timer, CNTV_CTL_EL0 = "); 27 | val = raw_read_cntv_ctl(); 28 | uart_puthex(val); 29 | gicd_clear_pending(TIMER_IRQ); 30 | uart_puts("\n\tSystem Frequency: CNTFRQ_EL0 = "); 31 | uart_puthex(cntfrq); 32 | 33 | // Next timer IRQ is after n sec. 34 | ticks = TIMER_WAIT * cntfrq; 35 | // Get value of the current timer 36 | current_cnt = raw_read_cntvct_el0(); 37 | uart_puts("\n\tCurrent counter: CNTVCT_EL0 = "); 38 | uart_puthex(current_cnt); 39 | // Set the interrupt in Current Time + TimerTick 40 | raw_write_cntv_cval_el0(current_cnt + ticks); 41 | uart_puts("\n\tAssert Timer IRQ after "); 42 | uart_puthex(TIMER_WAIT); 43 | uart_puts(" sec(s): CNTV_CVAL_EL0 = "); 44 | val = raw_read_cntv_cval_el0(); 45 | uart_puthex(val); 46 | 47 | // Enable the timer 48 | enable_cntv(); 49 | uart_puts("\n\tEnable the timer, CNTV_CTL_EL0 = "); 50 | val = raw_read_cntv_ctl(); 51 | uart_puthex(val); 52 | uart_puts("\n"); 53 | } 54 | #endif /* TIMER_DEBUG */ 55 | 56 | void timer_test(void) 57 | { 58 | uint32_t val; 59 | uint64_t ticks, current_cnt; 60 | 61 | uart_puts("timer_test\n"); 62 | // GIC Init 63 | gic_v3_initialize(); 64 | 65 | uart_puts("CurrentEL = "); 66 | val = raw_read_current_el(); 67 | uart_puthex(val); 68 | 69 | uart_puts("\nRVBAR_EL1 = "); 70 | val = raw_read_rvbar_el1(); 71 | uart_puthex(val); 72 | 73 | uart_puts("\nVBAR_EL1 = "); 74 | val = raw_read_vbar_el1(); 75 | uart_puthex(val); 76 | 77 | uart_puts("\nDAIF = "); 78 | val = raw_read_daif(); 79 | uart_puthex(val); 80 | 81 | // Disable the timer 82 | disable_cntv(); 83 | uart_puts("\nDisable the timer, CNTV_CTL_EL0 = "); 84 | val = raw_read_cntv_ctl(); 85 | uart_puthex(val); 86 | uart_puts("\nSystem Frequency: CNTFRQ_EL0 = "); 87 | cntfrq = raw_read_cntfrq_el0(); 88 | uart_puthex(cntfrq); 89 | 90 | // Next timer IRQ is after n sec(s). 91 | ticks = TIMER_WAIT * cntfrq; 92 | // Get value of the current timer 93 | current_cnt = raw_read_cntvct_el0(); 94 | uart_puts("\nCurrent counter: CNTVCT_EL0 = "); 95 | uart_puthex(current_cnt); 96 | // Set the interrupt in Current Time + TimerTick 97 | raw_write_cntv_cval_el0(current_cnt + ticks); 98 | uart_puts("\nAssert Timer IRQ after 1 sec: CNTV_CVAL_EL0 = "); 99 | val = raw_read_cntv_cval_el0(); 100 | uart_puthex(val); 101 | 102 | // Enable the timer 103 | enable_cntv(); 104 | uart_puts("\nEnable the timer, CNTV_CTL_EL0 = "); 105 | val = raw_read_cntv_ctl(); 106 | uart_puthex(val); 107 | 108 | // Enable IRQ 109 | enable_irq(); 110 | uart_puts("\nEnable IRQ, DAIF = "); 111 | val = raw_read_daif(); 112 | uart_puthex(val); 113 | uart_puts("\n"); 114 | 115 | #if TIMER_DEBUG // Observe CNTP_CTL_EL0[2]: ISTATUS 116 | while(1){ 117 | current_cnt = raw_read_cntvct_el0(); 118 | val = raw_read_cntv_ctl(); 119 | uart_puts("\nCNTVCT_EL0 = "); 120 | uart_puthex(current_cnt); 121 | uart_puts(", CNTV_CTL_EL0 = "); 122 | uart_puthex(val); 123 | val = raw_read_spsr_el1(); 124 | uart_puts(", SPSR_EL1 = "); 125 | uart_puthex(val); 126 | val = raw_read_isr_el1(); 127 | uart_puts(", ISR_EL1 = "); 128 | uart_puthex(val); 129 | uart_puts("\n"); 130 | } 131 | #else 132 | while(1){ 133 | wfi(); /* Wait for Interrupt */ 134 | } 135 | #endif 136 | } 137 | -------------------------------------------------------------------------------- /timer.h: -------------------------------------------------------------------------------- 1 | #if !defined(_TIMER_H) 2 | #define _TIMER_H 3 | 4 | void timer_test(void); 5 | 6 | #endif /* _TIMER_H */ 7 | -------------------------------------------------------------------------------- /uart.c: -------------------------------------------------------------------------------- 1 | #include "uart.h" 2 | 3 | volatile unsigned int * const UART0DR = (unsigned int *) 0x09000000; 4 | volatile unsigned int * const UART0FR = (unsigned int *) 0x09000018; 5 | 6 | 7 | void uart_putc(const char c) 8 | { 9 | // Wait for UART to become ready to transmit. 10 | while ((*UART0FR) & (1 << 5)) { } 11 | *UART0DR = c; /* Transmit char */ 12 | } 13 | 14 | void uart_puthex(uint64_t n) 15 | { 16 | const char *hexdigits = "0123456789ABCDEF"; 17 | 18 | uart_putc('0'); 19 | uart_putc('x'); 20 | for (int i = 60; i >= 0; i -= 4){ 21 | uart_putc(hexdigits[(n >> i) & 0xf]); 22 | if (i == 32) 23 | uart_putc(' '); 24 | } 25 | } 26 | 27 | void uart_puts(const char *s) { 28 | for (int i = 0; s[i] != '\0'; i ++) 29 | uart_putc((unsigned char)s[i]); 30 | } 31 | 32 | -------------------------------------------------------------------------------- /uart.h: -------------------------------------------------------------------------------- 1 | #if !defined(_UART_H) 2 | #define _UART_H 3 | #include 4 | 5 | void uart_putc(const char c); 6 | void uart_puthex(uint64_t n); 7 | void uart_puts(const char *s); 8 | 9 | #endif /* _UART_H */ 10 | -------------------------------------------------------------------------------- /vector.S: -------------------------------------------------------------------------------- 1 | /* -*- mode: asm; coding:utf-8 -*- */ 2 | /************************************************************************/ 3 | /* OS kernel sample */ 4 | /* Copyright 2014 Takeharu KATO */ 5 | /* */ 6 | /* Exception vector */ 7 | /* */ 8 | /************************************************************************/ 9 | #define ASM_FILE 1 10 | 11 | #include "exception.h" 12 | 13 | .section ".text.boot" 14 | 15 | .macro build_trapframe exc_type 16 | /* 17 | * store generic registers from (x29,x30) pair to (x1,x2) pair. 18 | */ 19 | stp x29, x30, [sp, #-16]! 20 | stp x27, x28, [sp, #-16]! 21 | stp x25, x26, [sp, #-16]! 22 | stp x23, x24, [sp, #-16]! 23 | stp x21, x22, [sp, #-16]! 24 | stp x19, x20, [sp, #-16]! 25 | stp x17, x18, [sp, #-16]! 26 | stp x15, x16, [sp, #-16]! 27 | stp x13, x14, [sp, #-16]! 28 | stp x11, x12, [sp, #-16]! 29 | stp x9, x10, [sp, #-16]! 30 | stp x7, x8, [sp, #-16]! 31 | stp x5, x6, [sp, #-16]! 32 | stp x3, x4, [sp, #-16]! 33 | stp x1, x2, [sp, #-16]! 34 | /* 35 | * Store (spsr, x0) 36 | */ 37 | mrs x21, spsr_el1 38 | stp x21, x0, [sp, #-16]! 39 | /* 40 | * Allocate a room for sp_el0 and store elr 41 | */ 42 | mrs x21, elr_el1 43 | stp xzr, x21, [sp, #-16]! 44 | /* 45 | * store exception type and esr 46 | */ 47 | mov x21, #(\exc_type) 48 | mrs x22, esr_el1 49 | stp x21, x22, [sp, #-16]! 50 | .endm 51 | 52 | .macro store_traped_sp 53 | mrs x21, sp_el0 54 | str x21, [sp, #EXC_EXC_SP_OFFSET] 55 | .endm 56 | 57 | .macro call_common_trap_handler 58 | mov x0, sp 59 | bl common_trap_handler 60 | .endm 61 | 62 | .macro store_nested_sp 63 | mov x21, sp 64 | add x21, x21, #EXC_FRAME_SIZE 65 | str x21, [sp, #EXC_EXC_SP_OFFSET] 66 | .endm 67 | 68 | .macro restore_traped_sp 69 | ldr x21, [sp, #EXC_EXC_SP_OFFSET] 70 | msr sp_el0, x21 71 | .endm 72 | 73 | .macro restore_trapframe 74 | 75 | /* 76 | * Drop exception type, esr, 77 | */ 78 | add sp, sp, #16 79 | /* 80 | * Drop exception stack pointer and restore elr_el1 81 | */ 82 | ldp x21, x22, [sp], #16 83 | msr elr_el1, x22 84 | 85 | /* 86 | * Retore spsr and x0 87 | */ 88 | ldp x21, x0, [sp], #16 89 | msr spsr_el1, x21 90 | 91 | /* 92 | * Restore generic registers from (x29,x30) pair to (x1,x2) pair. 93 | */ 94 | ldp x1, x2, [sp], #16 95 | ldp x3, x4, [sp], #16 96 | ldp x5, x6, [sp], #16 97 | ldp x7, x8, [sp], #16 98 | ldp x9, x10, [sp], #16 99 | ldp x11, x12, [sp], #16 100 | ldp x13, x14, [sp], #16 101 | ldp x15, x16, [sp], #16 102 | ldp x17, x18, [sp], #16 103 | ldp x19, x20, [sp], #16 104 | ldp x21, x22, [sp], #16 105 | ldp x23, x24, [sp], #16 106 | ldp x25, x26, [sp], #16 107 | ldp x27, x28, [sp], #16 108 | ldp x29, x30, [sp], #16 109 | 110 | eret 111 | .endm 112 | 113 | /* 114 | * Exception vectors. 115 | */ 116 | vector_table_align 117 | .globl vectors 118 | vectors: 119 | /* 120 | * Current EL with SP0 121 | */ 122 | vector_entry_align 123 | b _curr_el_sp0_sync /* Synchronous */ 124 | vector_entry_align 125 | b _curr_el_sp0_irq /* IRQ/vIRQ */ 126 | vector_entry_align 127 | b _curr_el_sp0_fiq /* FIQ/vFIQ */ 128 | vector_entry_align 129 | b _curr_el_sp0_serror /* SError/vSError */ 130 | 131 | /* 132 | * Current EL with SPx 133 | */ 134 | vector_entry_align 135 | b _curr_el_spx_sync /* Synchronous */ 136 | vector_entry_align 137 | b _curr_el_spx_irq /* IRQ/vIRQ */ 138 | vector_entry_align 139 | b _curr_el_spx_fiq /* FIQ/vFIQ */ 140 | vector_entry_align 141 | b _curr_el_spx_serror /* SError/vSError */ 142 | 143 | /* 144 | * Lower EL using AArch64 145 | */ 146 | vector_entry_align 147 | b _lower_el_aarch64_sync 148 | vector_entry_align 149 | b _lower_el_aarch64_irq 150 | vector_entry_align 151 | b _lower_el_aarch64_fiq 152 | vector_entry_align 153 | b _lower_el_aarch64_serror 154 | 155 | /* 156 | * Lower EL using AArch32 157 | */ 158 | vector_entry_align 159 | b _lower_el_aarch32_sync 160 | vector_entry_align 161 | b _lower_el_aarch32_irq 162 | vector_entry_align 163 | b _lower_el_aarch32_fiq 164 | vector_entry_align 165 | b _lower_el_aarch32_serror 166 | 167 | 168 | text_align 169 | _curr_el_sp0_sync: 170 | build_trapframe AARCH64_EXC_SYNC_SP0 171 | store_traped_sp 172 | call_common_trap_handler 173 | restore_traped_sp 174 | restore_trapframe 175 | 176 | text_align 177 | _curr_el_sp0_irq: 178 | build_trapframe AARCH64_EXC_IRQ_SP0 179 | store_traped_sp 180 | call_common_trap_handler 181 | restore_traped_sp 182 | restore_trapframe 183 | 184 | text_align 185 | _curr_el_sp0_fiq: 186 | build_trapframe AARCH64_EXC_FIQ_SP0 187 | store_traped_sp 188 | call_common_trap_handler 189 | restore_traped_sp 190 | restore_trapframe 191 | 192 | text_align 193 | _curr_el_sp0_serror: 194 | build_trapframe AARCH64_EXC_SERR_SP0 195 | store_traped_sp 196 | call_common_trap_handler 197 | restore_traped_sp 198 | restore_trapframe 199 | 200 | 201 | text_align 202 | _curr_el_spx_sync: 203 | build_trapframe AARCH64_EXC_SYNC_SPX 204 | store_nested_sp 205 | call_common_trap_handler 206 | restore_trapframe 207 | 208 | text_align 209 | _curr_el_spx_irq: 210 | build_trapframe AARCH64_EXC_IRQ_SPX 211 | store_nested_sp 212 | call_common_trap_handler 213 | restore_trapframe 214 | 215 | text_align 216 | _curr_el_spx_fiq: 217 | build_trapframe AARCH64_EXC_FIQ_SPX 218 | store_nested_sp 219 | call_common_trap_handler 220 | restore_trapframe 221 | 222 | text_align 223 | _curr_el_spx_serror: 224 | build_trapframe AARCH64_EXC_SERR_SPX 225 | store_nested_sp 226 | call_common_trap_handler 227 | restore_trapframe 228 | 229 | 230 | text_align 231 | _lower_el_aarch64_sync: 232 | build_trapframe AARCH64_EXC_SYNC_AARCH64 233 | store_traped_sp 234 | call_common_trap_handler 235 | restore_traped_sp 236 | restore_trapframe 237 | 238 | text_align 239 | _lower_el_aarch64_irq: 240 | build_trapframe AARCH64_EXC_IRQ_AARCH64 241 | store_traped_sp 242 | call_common_trap_handler 243 | restore_traped_sp 244 | restore_trapframe 245 | 246 | text_align 247 | _lower_el_aarch64_fiq: 248 | build_trapframe AARCH64_EXC_FIQ_AARCH64 249 | store_traped_sp 250 | call_common_trap_handler 251 | restore_traped_sp 252 | restore_trapframe 253 | 254 | text_align 255 | _lower_el_aarch64_serror: 256 | build_trapframe AARCH64_EXC_SERR_AARCH64 257 | store_traped_sp 258 | call_common_trap_handler 259 | restore_traped_sp 260 | restore_trapframe 261 | 262 | 263 | text_align 264 | _lower_el_aarch32_sync: 265 | build_trapframe AARCH64_EXC_SYNC_AARCH32 266 | store_traped_sp 267 | call_common_trap_handler 268 | restore_traped_sp 269 | restore_trapframe 270 | 271 | text_align 272 | _lower_el_aarch32_irq: 273 | build_trapframe AARCH64_EXC_IRQ_AARCH32 274 | store_traped_sp 275 | call_common_trap_handler 276 | restore_traped_sp 277 | restore_trapframe 278 | 279 | text_align 280 | _lower_el_aarch32_fiq: 281 | build_trapframe AARCH64_EXC_FIQ_AARCH32 282 | store_traped_sp 283 | call_common_trap_handler 284 | restore_traped_sp 285 | restore_trapframe 286 | 287 | text_align 288 | _lower_el_aarch32_serror: 289 | build_trapframe AARCH64_EXC_SERR_AARCH32 290 | store_traped_sp 291 | call_common_trap_handler 292 | restore_traped_sp 293 | restore_trapframe 294 | 295 | --------------------------------------------------------------------------------