diff options
| author | Bernard Xiong <[email protected]> | 2014-04-03 18:07:17 +0800 |
|---|---|---|
| committer | Bernard Xiong <[email protected]> | 2014-04-03 18:07:17 +0800 |
| commit | 16eb9bbed5dde151dabba2b9bc9cb13753873940 (patch) | |
| tree | 5a2ab75c4b9c33b476e5838a06e89d3e43ff9d54 /libcpu | |
| parent | 8bd3e6f6dc2a6b73d53558f33d684bada0654c06 (diff) | |
| parent | 28f11fdd7bdc43855081c274a65bc98372002226 (diff) | |
Merge pull request #253 from grissiom/qemu-realview-vmm
[vmm] add realview-pb-a8 VMM support
Diffstat (limited to 'libcpu')
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/SConscript | 17 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/armv7.h | 64 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/context_gcc.S | 175 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/cp15.h | 12 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/cp15_gcc.S | 140 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/cpu.c | 37 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/gic.c | 313 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/gic.h | 35 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/interrupt.c | 144 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/interrupt.h | 50 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/mmu.c | 207 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/pmu.c | 12 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/pmu.h | 151 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/stack.c | 65 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/start_gcc.S | 366 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/trap.c | 204 | ||||
| -rw-r--r-- | libcpu/arm/realview-a8-vmm/vector_gcc.S | 66 |
17 files changed, 2058 insertions, 0 deletions
diff --git a/libcpu/arm/realview-a8-vmm/SConscript b/libcpu/arm/realview-a8-vmm/SConscript new file mode 100644 index 0000000000..61057c04cc --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/SConscript @@ -0,0 +1,17 @@ +Import('rtconfig') +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +if rtconfig.PLATFORM == 'iar': + src += Glob('*_iar.S') +elif rtconfig.PLATFORM == 'gcc': + src += Glob('*_gcc.S') +elif rtconfig.PLATFORM == 'armcc': + src += Glob('*_rvds.S') + +group = DefineGroup('AM335x', src, depend = [''], CPPPATH = CPPPATH) + +Return('group') diff --git a/libcpu/arm/realview-a8-vmm/armv7.h b/libcpu/arm/realview-a8-vmm/armv7.h new file mode 100644 index 0000000000..69c556eb3c --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/armv7.h @@ -0,0 +1,64 @@ +#ifndef __ARMV7_H__ +#define __ARMV7_H__ + +/* the exception stack without VFP registers */ +struct rt_hw_exp_stack +{ + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long sp; + unsigned long lr; + unsigned long pc; + unsigned long cpsr; +}; + +struct rt_hw_stack +{ + unsigned long cpsr; + unsigned long r0; + unsigned long r1; + unsigned long r2; + unsigned long r3; + unsigned long r4; + unsigned long r5; + unsigned long r6; + unsigned long r7; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long fp; + unsigned long ip; + unsigned long lr; + unsigned long pc; +}; + +#define USERMODE 0x10 +#define FIQMODE 0x11 +#define IRQMODE 0x12 +#define SVCMODE 0x13 +#define MONITORMODE 0x16 +#define ABORTMODE 0x17 +#define HYPMODE 0x1b +#define UNDEFMODE 0x1b +#define MODEMASK 0x1f +#define NOINT 0xc0 + +#define T_Bit (1<<5) +#define F_Bit (1<<6) +#define I_Bit (1<<7) +#define A_Bit (1<<8) +#define E_Bit (1<<9) +#define J_Bit (1<<24) + +#endif diff --git a/libcpu/arm/realview-a8-vmm/context_gcc.S b/libcpu/arm/realview-a8-vmm/context_gcc.S new file mode 100644 index 0000000000..9bb31e3f10 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/context_gcc.S @@ -0,0 +1,175 @@ +/* + * File : context.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +#include <rtconfig.h> + +#ifdef RT_USING_VMM +#include <vmm.h> +#endif + +.section .text, "ax" +/* + * rt_base_t rt_hw_interrupt_disable(); + */ +.globl rt_hw_interrupt_disable +rt_hw_interrupt_disable: + mrs r0, cpsr + cpsid i + bx lr + +/* + * void rt_hw_interrupt_enable(rt_base_t level); + */ +.globl rt_hw_interrupt_enable +rt_hw_interrupt_enable: + msr cpsr, r0 + bx lr + +/* + * void rt_hw_context_switch_to(rt_uint32 to); + * r0 --> to + */ +.globl rt_hw_context_switch_to +rt_hw_context_switch_to: + ldr sp, [r0] @ get new task stack pointer + + ldmfd sp!, {r4} @ pop new task spsr + msr spsr_cxsf, r4 + + bic r4, r4, #0x20 @ must be ARM mode + msr cpsr_cxsf, r4 + + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc + +.section .bss.share.isr +_guest_switch_lvl: + .word 0 + +.globl vmm_virq_update + +.section .text.isr, "ax" +/* + * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to); + * r0 --> from + * r1 --> to + */ +.globl rt_hw_context_switch +rt_hw_context_switch: + stmfd sp!, {lr} @ push pc (lr should be pushed in place of PC) + stmfd sp!, {r0-r12, lr} @ push lr & register file + + mrs r4, cpsr + tst lr, #0x01 + orrne r4, r4, #0x20 @ it's thumb code + + stmfd sp!, {r4} @ push cpsr + + str sp, [r0] @ store sp in preempted tasks TCB + ldr sp, [r1] @ get new task stack pointer + +#ifdef RT_USING_VMM +#ifdef RT_VMM_USING_DOMAIN + @ need to make sure we are in vmm domain as we would use rt_current_thread + ldr r2, =vmm_domain_val + ldr r7, [r2] + mcr p15, 0, r7, c3, c0 +#endif + + /* check whether vmm thread, otherwise, update vIRQ */ + ldr r3, =rt_current_thread + ldr r4, [r3] + ldr r5, =vmm_thread + cmp r4, r5 + beq switch_to_guest + + @ not falling into guest. Simple task ;-) + ldmfd sp!, {r6} @ pop new task cpsr to spsr + msr spsr_cxsf, r6 + ldmfd sp!, {r0-r12, lr, pc}^ + +switch_to_guest: +#ifdef RT_VMM_USING_DOMAIN + @ the stack is saved in the guest domain so we need to + @ come back to the guest domain to get the registers. + ldr r1, =super_domain_val + ldr r0, [r1] + mcr p15, 0, r0, c3, c0 +#endif + /* The user can do nearly anything in rt_thread_idle_excute because it will + call the thread->cleanup. One common thing is sending events and wake up + threads. So the guest thread will be preempted. This is the only point that + the guest thread would call rt_hw_context_switch and "yield". + + More over, rt_schedule will call this function and this function *will* + reentrant. If that happens, we need to make sure that call the + rt_thread_idle_excute and vmm_virq_update again and we are in super domain. + I use a "reference count" to achieve such behaviour. If you have better + idea, tell me. */ + ldr r4, =_guest_switch_lvl + ldr r5, [r4] + add r5, r5, #1 + str r5, [r4] + cmp r5, #1 + bne _switch_through + + bl rt_thread_idle_excute + bl vmm_virq_update + + /* we need _guest_switch_lvl to protect until _switch_through, but it's OK + * to cleanup the reference count here because the code below will not be + * reentrant. */ + sub r5, r5, #1 + str r5, [r4] + +#ifdef RT_VMM_USING_DOMAIN + ldr r1, =guest_domain_val + ldr r0, [r1] + mcr p15, 0, r0, c3, c0 +#endif +_switch_through: +#endif /* RT_USING_VMM */ + ldmfd sp!, {r4} @ pop new task cpsr to spsr + msr spsr_cxsf, r4 + ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr + +/* + * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to); + */ +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread +.globl rt_hw_context_switch_interrupt +rt_hw_context_switch_interrupt: + ldr r2, =rt_thread_switch_interrupt_flag + ldr r3, [r2] + cmp r3, #1 + beq _reswitch + ldr ip, =rt_interrupt_from_thread @ set rt_interrupt_from_thread + mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1 + str r0, [ip] + str r3, [r2] +_reswitch: + ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread + str r1, [r2] + bx lr diff --git a/libcpu/arm/realview-a8-vmm/cp15.h b/libcpu/arm/realview-a8-vmm/cp15.h new file mode 100644 index 0000000000..ebea3f0fe3 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/cp15.h @@ -0,0 +1,12 @@ +#ifndef __CP15_H__ +#define __CP15_H__ + +unsigned long rt_cpu_get_smp_id(void); + +void rt_cpu_mmu_disable(void); +void rt_cpu_mmu_enable(void); +void rt_cpu_tlb_set(volatile unsigned long*); + +void rt_cpu_vector_set_base(unsigned int addr); + +#endif diff --git a/libcpu/arm/realview-a8-vmm/cp15_gcc.S b/libcpu/arm/realview-a8-vmm/cp15_gcc.S new file mode 100644 index 0000000000..f1ed6492aa --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/cp15_gcc.S @@ -0,0 +1,140 @@ +/* + * File : cp15_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * http://www.rt-thread.org + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +.globl rt_cpu_get_smp_id +rt_cpu_get_smp_id: + mrc p15, #0, r0, c0, c0, #5 + bx lr + +.globl rt_cpu_vector_set_base +rt_cpu_vector_set_base: + mcr p15, #0, r0, c12, c0, #0 + dsb + bx lr + +.globl rt_hw_cpu_dcache_enable +rt_hw_cpu_dcache_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x00000004 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_hw_cpu_icache_enable +rt_hw_cpu_icache_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x00001000 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +_FLD_MAX_WAY: + .word 0x3ff +_FLD_MAX_IDX: + .word 0x7ff + +.globl rt_cpu_dcache_clean_flush +rt_cpu_dcache_clean_flush: + push {r4-r11} + dmb + mrc p15, #1, r0, c0, c0, #1 @ read clid register + ands r3, r0, #0x7000000 @ get level of coherency + mov r3, r3, lsr #23 + beq finished + mov r10, #0 +loop1: + add r2, r10, r10, lsr #1 + mov r1, r0, lsr r2 + and r1, r1, #7 + cmp r1, #2 + blt skip + mcr p15, #2, r10, c0, c0, #0 + isb + mrc p15, #1, r1, c0, c0, #0 + and r2, r1, #7 + add r2, r2, #4 + ldr r4, _FLD_MAX_WAY + ands r4, r4, r1, lsr #3 + clz r5, r4 + ldr r7, _FLD_MAX_IDX + ands r7, r7, r1, lsr #13 +loop2: + mov r9, r4 +loop3: + orr r11, r10, r9, lsl r5 + orr r11, r11, r7, lsl r2 + mcr p15, #0, r11, c7, c14, #2 + subs r9, r9, #1 + bge loop3 + subs r7, r7, #1 + bge loop2 +skip: + add r10, r10, #2 + cmp r3, r10 + bgt loop1 + +finished: + dsb + isb + pop {r4-r11} + bx lr + +.globl rt_hw_cpu_dcache_disable +rt_hw_cpu_dcache_disable: + push {r4-r11, lr} + bl rt_cpu_dcache_clean_flush + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x00000004 + mcr p15, #0, r0, c1, c0, #0 + pop {r4-r11, lr} + bx lr + +.globl rt_hw_cpu_icache_disable +rt_hw_cpu_icache_disable: + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #0x00001000 + mcr p15, #0, r0, c1, c0, #0 + bx lr + +.globl rt_cpu_mmu_disable +rt_cpu_mmu_disable: + mcr p15, #0, r0, c8, c7, #0 @ invalidate tlb + mrc p15, #0, r0, c1, c0, #0 + bic r0, r0, #1 + mcr p15, #0, r0, c1, c0, #0 @ clear mmu bit + dsb + bx lr + +.globl rt_cpu_mmu_enable +rt_cpu_mmu_enable: + mrc p15, #0, r0, c1, c0, #0 + orr r0, r0, #0x001 + mcr p15, #0, r0, c1, c0, #0 @ set mmu enable bit + dsb + bx lr + +.globl rt_cpu_tlb_set +rt_cpu_tlb_set: + mcr p15, #0, r0, c2, c0, #0 + dmb + bx lr diff --git a/libcpu/arm/realview-a8-vmm/cpu.c b/libcpu/arm/realview-a8-vmm/cpu.c new file mode 100644 index 0000000000..7dd426e4dd --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/cpu.c @@ -0,0 +1,37 @@ +/* + * File : cpu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2011-09-15 Bernard first version + */ + +#include <rthw.h> +#include <rtthread.h> +#include <board.h> + +/** + * @addtogroup AM33xx + */ +/*@{*/ + +/** shutdown CPU */ +void rt_hw_cpu_shutdown() +{ + rt_uint32_t level; + rt_kprintf("shutdown...\n"); + + level = rt_hw_interrupt_disable(); + while (level) + { + RT_ASSERT(0); + } +} + +/*@}*/ diff --git a/libcpu/arm/realview-a8-vmm/gic.c b/libcpu/arm/realview-a8-vmm/gic.c new file mode 100644 index 0000000000..db26fc5dcf --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/gic.c @@ -0,0 +1,313 @@ +/* + * File : gic.c, ARM Generic Interrupt Controller + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013-2014, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-07-20 Bernard first version + * 2014-04-03 Grissiom many enhancements + */ + +#include <rtthread.h> +#include <board.h> + +#include "gic.h" +#include "cp15.h" + +struct arm_gic +{ + rt_uint32_t offset; + + rt_uint32_t dist_hw_base; + rt_uint32_t cpu_hw_base; +}; +static struct arm_gic _gic_table[ARM_GIC_MAX_NR]; + +#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00) +#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04) +#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08) +#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0c) +#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10) +#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14) +#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18) + +#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000) +#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004) +#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080 + ((n)/32) * 4) +#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100 + ((n)/32) * 4) +#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180 + ((n)/32) * 4) +#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200 + ((n)/32) * 4) +#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280 + ((n)/32) * 4) +#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300 + ((n)/32) * 4) +#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380 + ((n)/32) * 4) +#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400 + ((n)/4) * 4) +#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800 + ((n)/4) * 4) +#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00 + ((n)/16) * 4) +#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00) +#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10 + ((n)/4) * 4) +#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8) + +static unsigned int _gic_max_irq; + +int arm_gic_get_active_irq(rt_uint32_t index) +{ + int irq; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = GIC_CPU_INTACK(_gic_table[index].cpu_hw_base); + irq += _gic_table[index].offset; + return irq; +} + +void arm_gic_ack(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; + GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq; + GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_mask(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_clear_pending(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_clear_active(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask) +{ + rt_uint32_t old_tgt; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq); + + old_tgt &= ~(0x0FFUL << ((irq % 4)*8)); + old_tgt |= cpumask << ((irq % 4)*8); + + GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt; +} + +void arm_gic_umask(rt_uint32_t index, int irq) +{ + rt_uint32_t mask = 1 << (irq % 32); + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + irq = irq - _gic_table[index].offset; + RT_ASSERT(irq >= 0); + + GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask; +} + +void arm_gic_dump_type(rt_uint32_t index) +{ + unsigned int gic_type; + + gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base); + rt_kprintf("GICv%d on %p, max IRQs: %d, %s security extension(%08x)\n", + (GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4) & 0xf, + _gic_table[index].dist_hw_base, + _gic_max_irq, + gic_type & (1 << 10) ? "has" : "no", + gic_type); +} + +void arm_gic_dump(rt_uint32_t index) +{ + unsigned int i, k; + + k = GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base); + rt_kprintf("--- high pending priority: %d(%08x)\n", k, k); + rt_kprintf("--- hw mask ---\n"); + for (i = 0; i < _gic_max_irq / 32; i++) + { + rt_kprintf("0x%08x, ", + GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, + i * 32)); + } + rt_kprintf("\n--- hw pending ---\n"); + for (i = 0; i < _gic_max_irq / 32; i++) + { + rt_kprintf("0x%08x, ", + GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, + i * 32)); + } + rt_kprintf("\n--- hw active ---\n"); + for (i = 0; i < _gic_max_irq / 32; i++) + { + rt_kprintf("0x%08x, ", + GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, + i * 32)); + } + rt_kprintf("\n"); +} +#ifdef RT_USING_FINSH +#include <finsh.h> +FINSH_FUNCTION_EXPORT_ALIAS(arm_gic_dump, gic, show gic status); +#endif + +int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start) +{ + unsigned int gic_type, i; + rt_uint32_t cpumask = 1 << 0; + + RT_ASSERT(index < ARM_GIC_MAX_NR); + + _gic_table[index].dist_hw_base = dist_base; + _gic_table[index].offset = irq_start; + + /* Find out how many interrupts are supported. */ + gic_type = GIC_DIST_TYPE(dist_base); + _gic_max_irq = ((gic_type & 0x1f) + 1) * 32; + + /* + * The GIC only supports up to 1020 interrupt sources. + * Limit this to either the architected maximum, or the + * platform maximum. + */ + if (_gic_max_irq > 1020) + _gic_max_irq = 1020; + if (_gic_max_irq > ARM_GIC_NR_IRQS) + _gic_max_irq = ARM_GIC_NR_IRQS; + +#ifndef RT_PRETENT_AS_CPU0 + /* If we are run on the second core, the GIC should have already been setup + * by BootStrapProcessor. */ + if ((rt_cpu_get_smp_id() & 0xF) != 0) + return 0; +#endif +#ifdef RT_USING_VMM + return 0; +#endif + + cpumask |= cpumask << 8; + cpumask |= cpumask << 16; + + GIC_DIST_CTRL(dist_base) = 0x0; + + /* Set all global interrupts to be level triggered, active low. */ + for (i = 32; i < _gic_max_irq; i += 16) + GIC_DIST_CONFIG(dist_base, i) = 0x0; + + /* Set all global interrupts to this CPU only. */ + for (i = 32; i < _gic_max_irq; i += 4) + GIC_DIST_TARGET(dist_base, i) = cpumask; + + /* Set priority on all interrupts. */ + for (i = 0; i < _gic_max_irq; i += 4) + GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0; + + /* Disable all interrupts. */ + for (i = 0; i < _gic_max_irq; i += 32) + GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffff; + /* All interrupts defaults to IGROUP1(IRQ). */ + for (i = 0; i < _gic_max_irq; i += 32) + GIC_DIST_IGROUP(dist_base, i) = 0xffffffff; + + return 0; +} + +int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base) +{ + RT_ASSERT(index < ARM_GIC_MAX_NR); + + _gic_table[index].cpu_hw_base = cpu_base; + +#ifndef RT_PRETENT_AS_CPU0 + /* If we are run on the second core, the GIC should have already been setup + * by BootStrapProcessor. */ + if ((rt_cpu_get_smp_id() & 0xF) != 0) + return 0; +#endif +#ifdef RT_USING_VMM + return 0; +#endif + + GIC_CPU_PRIMASK(cpu_base) = 0xf0; + /* Enable CPU interrupt */ + GIC_CPU_CTRL(cpu_base) = 0x01; + + return 0; +} + +void arm_gic_set_group(rt_uint32_t index, int vector, int group) +{ + /* As for GICv2, there are only group0 and group1. */ + RT_ASSERT(group <= 1); + RT_ASSERT(vector < _gic_max_irq); + + if (group == 0) + { + GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, + vector) &= ~(1 << (vector % 32)); + } + else if (group == 1) + { + GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, + vector) |= (1 << (vector % 32)); + } +} + +void arm_gic_trigger(rt_uint32_t index, int target_cpu, int irq) +{ + unsigned int reg; + + RT_ASSERT(irq <= 15); + RT_ASSERT(target_cpu <= 255); + + reg = (target_cpu << 16) | irq; + GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = reg; +} + +void arm_gic_clear_sgi(rt_uint32_t index, int target_cpu, int irq) +{ + RT_ASSERT(irq <= 15); + RT_ASSERT(target_cpu <= 255); + + GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = target_cpu << (irq % 4); +} diff --git a/libcpu/arm/realview-a8-vmm/gic.h b/libcpu/arm/realview-a8-vmm/gic.h new file mode 100644 index 0000000000..41a7727da2 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/gic.h @@ -0,0 +1,35 @@ +/* + * File : gic.h, ARM Generic Interrupt Controller + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-07-20 Bernard first version + */ + +#ifndef __GIC_H__ +#define __GIC_H__ + +int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start); +int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base); + +void arm_gic_mask(rt_uint32_t index, int irq); +void arm_gic_umask(rt_uint32_t index, int irq); +void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask); +void arm_gic_set_group(rt_uint32_t index, int vector, int group); + +int arm_gic_get_active_irq(rt_uint32_t index); +void arm_gic_ack(rt_uint32_t index, int irq); + +void arm_gic_trigger(rt_uint32_t index, int target_cpu, int irq); +void arm_gic_clear_sgi(rt_uint32_t index, int target_cpu, int irq); + +void arm_gic_dump_type(rt_uint32_t index); + +#endif + diff --git a/libcpu/arm/realview-a8-vmm/interrupt.c b/libcpu/arm/realview-a8-vmm/interrupt.c new file mode 100644 index 0000000000..ffb6c10a89 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/interrupt.c @@ -0,0 +1,144 @@ +/* + * File : interrupt.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013-2014, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-07-06 Bernard first version + * 2014-04-03 Grissiom port to VMM + */ + +#include <rthw.h> +#include <rtthread.h> +#include "realview.h" +#include "gic.h" + +#ifdef RT_USING_VMM +#include <vmm.h> +#endif + +#define MAX_HANDLERS NR_IRQS_PBA8 + +extern volatile rt_uint8_t rt_interrupt_nest; + +/* exception and interrupt handler table */ +struct rt_irq_desc isr_table[MAX_HANDLERS]; + +/* Those varibles will be accessed in ISR, so we need to share them. */ +rt_uint32_t rt_interrupt_from_thread SECTION(".bss.share.int"); +rt_uint32_t rt_interrupt_to_thread SECTION(".bss.share.int"); +rt_uint32_t rt_thread_switch_interrupt_flag SECTION(".bss.share.int"); + +const unsigned int VECTOR_BASE = 0x00; +extern void rt_cpu_vector_set_base(unsigned int addr); +extern int system_vectors; + +static void rt_hw_vector_init(void) +{ +#ifndef RT_USING_VMM + unsigned int *dest = (unsigned int *)VECTOR_BASE; + unsigned int *src = (unsigned int *)&system_vectors; + + rt_memcpy(dest, src, 16 * 4); + rt_cpu_vector_set_base(VECTOR_BASE); +#endif +} + +/** + * This function will initialize hardware interrupt + */ +void rt_hw_interrupt_init(void) +{ + rt_uint32_t gic_cpu_base; + rt_uint32_t gic_dist_base; + + /* initialize vector table */ + rt_hw_vector_init(); + + /* initialize exceptions table */ + rt_memset(isr_table, 0x00, sizeof(isr_table)); + + /* initialize ARM GIC */ +#ifdef RT_USING_VMM + gic_dist_base = vmm_find_iomap("GIC_DIST"); + gic_cpu_base = vmm_find_iomap("GIC_CPU"); +#else + gic_dist_base = REALVIEW_GIC_DIST_BASE; + gic_cpu_base = REALVIEW_GIC_CPU_BASE; +#endif + arm_gic_dist_init(0, gic_dist_base, 0); + arm_gic_cpu_init(0, gic_cpu_base); + /*arm_gic_dump_type(0);*/ + + /* init interrupt nest, and context in thread sp */ + rt_interrupt_nest = 0; + rt_interrupt_from_thread = 0; + rt_interrupt_to_thread = 0; + rt_thread_switch_interrupt_flag = 0; +} + +/** + * This function will mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_mask(int vector) +{ + arm_gic_mask(0, vector); +} + +/** + * This function will un-mask a interrupt. + * @param vector the interrupt number + */ +void rt_hw_interrupt_umask(int vector) +{ + arm_gic_umask(0, vector); +} + +/** + * This function will install a interrupt service routine to a interrupt. + * @param vector the interrupt number + * @param new_handler the interrupt service routine to be installed + * @param old_handler the old interrupt service routine + */ +rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler, + void *param, char *name) +{ + rt_isr_handler_t old_handler = RT_NULL; + + if (vector < MAX_HANDLERS) + { + old_handler = isr_table[vector].handler; + + if (handler != RT_NULL) + { +#ifdef RT_USING_INTERRUPT_INFO + rt_strncpy(isr_table[vector].name, name, RT_NAME_MAX); +#endif /* RT_USING_INTERRUPT_INFO */ + isr_table[vector].handler = handler; + isr_table[vector].param = param; + } + } + + return old_handler; +} + +/** + * Trigger a software IRQ + * + * Since we are running in single core, the target CPU are always CPU0. + */ +void rt_hw_interrupt_trigger(int vector) +{ + arm_gic_trigger(0, 1, vector); +} + +void rt_hw_interrupt_clear(int vector) +{ + arm_gic_clear_sgi(0, 1, vector); +} diff --git a/libcpu/arm/realview-a8-vmm/interrupt.h b/libcpu/arm/realview-a8-vmm/interrupt.h new file mode 100644 index 0000000000..d81f1c81ae --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/interrupt.h @@ -0,0 +1,50 @@ +/* + * File : interrupt.h + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2011, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-07-06 Bernard first version + */ + +#ifndef __INTERRUPT_H__ +#define __INTERRUPT_H__ + +#define INT_IRQ 0x00 +#define INT_FIQ 0x01 + +#define INTC_REVISION(hw_base) REG32((hw_base) + 0x0) +#define INTC_SYSCONFIG(hw_base) REG32((hw_base) + 0x10) +#define INTC_SYSSTATUS(hw_base) REG32((hw_base) + 0x14) +#define INTC_SIR_IRQ(hw_base) REG32((hw_base) + 0x40) +#define INTC_SIR_FIQ(hw_base) REG32((hw_base) + 0x44) +#define INTC_CONTROL(hw_base) REG32((hw_base) + 0x48) +#define INTC_PROTECTION(hw_base) REG32((hw_base) + 0x4c) +#define INTC_IDLE(hw_base) REG32((hw_base) + 0x50) +#define INTC_IRQ_PRIORITY(hw_base) REG32((hw_base) + 0x60) +#define INTC_FIQ_PRIORITY(hw_base) REG32((hw_base) + 0x64) +#define INTC_THRESHOLD(hw_base) REG32((hw_base) + 0x68) +#define INTC_SICR(hw_base) REG32((hw_base) + 0x6c) +#define INTC_SCR(hw_base, n) REG32((hw_base) + 0x70 + ((n) * 0x04)) +#define INTC_ITR(hw_base, n) REG32((hw_base) + 0x80 + ((n) * 0x20)) +#define INTC_MIR(hw_base, n) REG32((hw_base) + 0x84 + ((n) * 0x20)) +#define INTC_MIR_CLEAR(hw_base, n) REG32((hw_base) + 0x88 + ((n) * 0x20)) +#define INTC_MIR_SET(hw_base, n) REG32((hw_base) + 0x8c + ((n) * 0x20)) +#define INTC_ISR_SET(hw_base, n) REG32((hw_base) + 0x90 + ((n) * 0x20)) +#define INTC_ISR_CLEAR(hw_base, n) REG32((hw_base) + 0x94 + ((n) * 0x20)) +#define INTC_PENDING_IRQ(hw_base, n) REG32((hw_base) + 0x98 + ((n) * 0x20)) +#define INTC_PENDING_FIQ(hw_base, n) REG32((hw_base) + 0x9c + ((n) * 0x20)) +#define INTC_ILR(hw_base, n) REG32((hw_base) + 0x100 + ((n) * 0x04)) + +void rt_hw_interrupt_control(int vector, int priority, int route); +int rt_hw_interrupt_get_active(int fiq_irq); +void rt_hw_interrupt_ack(int fiq_irq); +void rt_hw_interrupt_trigger(int vector); +void rt_hw_interrupt_clear(int vector); + +#endif diff --git a/libcpu/arm/realview-a8-vmm/mmu.c b/libcpu/arm/realview-a8-vmm/mmu.c new file mode 100644 index 0000000000..b2503e4260 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/mmu.c @@ -0,0 +1,207 @@ +/* + * File : mmu.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2006, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2012-01-10 bernard porting to AM1808 + */ + +#include <rtthread.h> +#include <rthw.h> +#include <board.h> + +#include "cp15.h" + +#define DESC_SEC (0x2) +#define CB (3<<2) //cache_on, write_back +#define CNB (2<<2) //cache_on, write_through +#define NCB (1<<2) //cache_off,WR_BUF on +#define NCNB (0<<2) //cache_off,WR_BUF off +#define AP_RW (3<<10) //supervisor=RW, user=RW +#define AP_RO (2<<10) //supervisor=RW, user=RO +#define XN (1<<4) // eXecute Never + +#define DOMAIN_FAULT (0x0) +#define DOMAIN_CHK (0x1) +#define DOMAIN_NOTCHK (0x3) +#define DOMAIN0 (0x0<<5) +#define DOMAIN1 (0x1<<5) + +#define DOMAIN0_ATTR (DOMAIN_CHK<<0) +#define DOMAIN1_ATTR (DOMAIN_FAULT<<2) + +/* Read/Write, cache, write back */ +#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) +/* Read/Write, cache, write through */ +#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) +/* Read/Write without cache and write buffer */ +#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) +/* Read/Write without cache and write buffer, no execute */ +#define RW_NCNBXN (AP_RW|DOMAIN0|NCNB|DESC_SEC|XN) +/* Read/Write without cache and write buffer */ +#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) + +/* dump 2nd level page table */ +void rt_hw_cpu_dump_page_table_2nd(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + for (i = 0; i < 256; i++) + { + rt_uint32_t pte2 = ptb[i]; + if ((pte2 & 0x3) == 0) + { + if (fcnt == 0) + rt_kprintf(" "); + rt_kprintf("%04x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf(" %04x: %x: ", i, pte2); + if ((pte2 & 0x3) == 0x1) + { + rt_kprintf("L,ap:%x,xn:%d,texcb:%02x\n", + ((pte2 >> 7) | (pte2 >> 4))& 0xf, + (pte2 >> 15) & 0x1, + ((pte2 >> 10) | (pte2 >> 2)) & 0x1f); + } + else + { + rt_kprintf("S,ap:%x,xn:%d,texcb:%02x\n", + ((pte2 >> 7) | (pte2 >> 4))& 0xf, pte2 & 0x1, + ((pte2 >> 4) | (pte2 >> 2)) & 0x1f); + } + } +} + +void rt_hw_cpu_dump_page_table(rt_uint32_t *ptb) +{ + int i; + int fcnt = 0; + + rt_kprintf("page table@%p\n", ptb); + for (i = 0; i < 1024*4; i++) + { + rt_uint32_t pte1 = ptb[i]; + if ((pte1 & 0x3) == 0) + { + rt_kprintf("%03x: ", i); + fcnt++; + if (fcnt == 16) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + continue; + } + if (fcnt != 0) + { + rt_kprintf("fault\n"); + fcnt = 0; + } + + rt_kprintf("%03x: %08x: ", i, pte1); + if ((pte1 & 0x3) == 0x3) + { + rt_kprintf("LPAE\n"); + } + else if ((pte1 & 0x3) == 0x1) + { + rt_kprintf("pte,ns:%d,domain:%d\n", + (pte1 >> 3) & 0x1, (pte1 >> 5) & 0xf); + /* + *rt_hw_cpu_dump_page_table_2nd((void*)((pte1 & 0xfffffc000) + * - 0x80000000 + 0xC0000000)); + */ + } + else if (pte1 & (1 << 18)) + { + rt_kprintf("super section,ns:%d,ap:%x,xn:%d,texcb:%02x\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + ((pte1 >> 10) | (pte1 >> 2)) & 0x1f); + } + else + { + rt_kprintf("section,ns:%d,ap:%x," + "xn:%d,texcb:%02x,domain:%d\n", + (pte1 >> 19) & 0x1, + ((pte1 >> 13) | (pte1 >> 10))& 0xf, + (pte1 >> 4) & 0x1, + (((pte1 & (0x7 << 12)) >> 10) | + ((pte1 & 0x0c) >> 2)) & 0x1f, + (pte1 >> 5) & 0xf); + } + } +} + +/* level1 page table, each entry for 1MB memory. */ +volatile static unsigned long MMUTable[4*1024] __attribute__((aligned(16*1024))); +void rt_hw_mmu_setmtt(rt_uint32_t vaddrStart, + rt_uint32_t vaddrEnd, + rt_uint32_t paddrStart, + rt_uint32_t attr) +{ + volatile rt_uint32_t *pTT; + volatile int i, nSec; + pTT = (rt_uint32_t *)MMUTable + (vaddrStart >> 20); + nSec = (vaddrEnd >> 20) - (vaddrStart >> 20); + for(i = 0; i <= nSec; i++) + { + *pTT = attr | (((paddrStart >> 20) + i) << 20); + pTT++; + } +} + +unsigned long rt_hw_set_domain_register(unsigned long domain_val) +{ + unsigned long old_domain; + + asm volatile ("mrc p15, 0, %0, c3, c0\n" : "=r" (old_domain)); + asm volatile ("mcr p15, 0, %0, c3, c0\n" : :"r" (domain_val) : "memory"); + + return old_domain; +} + +void rt_hw_mmu_init(void) +{ + rt_hw_cpu_dcache_disable(); + rt_hw_cpu_icache_disable(); + rt_cpu_mmu_disable(); + + /* set page table */ + /* 4G 1:1 memory */ + rt_hw_mmu_setmtt(0, 0xffffffff-1, 0, RW_CB); + /* IO memory region */ + rt_hw_mmu_setmtt(0x44000000, 0x80000000-1, 0x44000000, RW_NCNBXN); + + /*rt_hw_cpu_dump_page_table(MMUTable);*/ + rt_hw_set_domain_register(0x55555555); + + rt_cpu_tlb_set(MMUTable); + + rt_cpu_mmu_enable(); + + rt_hw_cpu_icache_enable(); + rt_hw_cpu_dcache_enable(); +} + diff --git a/libcpu/arm/realview-a8-vmm/pmu.c b/libcpu/arm/realview-a8-vmm/pmu.c new file mode 100644 index 0000000000..07911a2db7 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/pmu.c @@ -0,0 +1,12 @@ +#include <rtthread.h> +#include "pmu.h" + +void rt_hw_pmu_dump_feature(void) +{ + unsigned long reg; + + reg = rt_hw_pmu_get_control(); + rt_kprintf("ARM PMU Implementor: %c, ID code: %02x, %d counters\n", + reg >> 24, (reg >> 16) & 0xff, (reg >> 11) & 0x1f); + RT_ASSERT(ARM_PMU_CNTER_NR == ((reg >> 11) & 0x1f)); +} diff --git a/libcpu/arm/realview-a8-vmm/pmu.h b/libcpu/arm/realview-a8-vmm/pmu.h new file mode 100644 index 0000000000..05c1420dd8 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/pmu.h @@ -0,0 +1,151 @@ +#ifndef __PMU_H__ +#define __PMU_H__ + +#include "board.h" + +/* Number of counters */ +#define ARM_PMU_CNTER_NR 4 + +enum rt_hw_pmu_event_type { + ARM_PMU_EVENT_PMNC_SW_INCR = 0x00, + ARM_PMU_EVENT_L1_ICACHE_REFILL = 0x01, + ARM_PMU_EVENT_ITLB_REFILL = 0x02, + ARM_PMU_EVENT_L1_DCACHE_REFILL = 0x03, + ARM_PMU_EVENT_L1_DCACHE_ACCESS = 0x04, + ARM_PMU_EVENT_DTLB_REFILL = 0x05, + ARM_PMU_EVENT_MEM_READ = 0x06, + ARM_PMU_EVENT_MEM_WRITE = 0x07, + ARM_PMU_EVENT_INSTR_EXECUTED = 0x08, + ARM_PMU_EVENT_EXC_TAKEN = 0x09, + ARM_PMU_EVENT_EXC_EXECUTED = 0x0A, + ARM_PMU_EVENT_CID_WRITE = 0x0B, +}; + +/* Enable bit */ +#define ARM_PMU_PMCR_E (0x01 << 0) +/* Event counter reset */ +#define ARM_PMU_PMCR_P (0x01 << 1) +/* Cycle counter reset */ +#define ARM_PMU_PMCR_C (0x01 << 2) +/* Cycle counter divider */ +#define ARM_PMU_PMCR_D (0x01 << 3) + +#ifdef __GNUC__ +rt_inline void rt_hw_pmu_enable_cnt(int divide64) +{ + unsigned long pmcr; + unsigned long pmcntenset; + + asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + pmcr |= ARM_PMU_PMCR_E | ARM_PMU_PMCR_P | ARM_PMU_PMCR_C; + if (divide64) + pmcr |= ARM_PMU_PMCR_D; + else + pmcr &= ~ARM_PMU_PMCR_D; + asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr)); + + /* enable all the counters */ + pmcntenset = ~0; + asm volatile ("mcr p15, 0, %0, c9, c12, 1" :: "r"(pmcntenset)); + /* clear overflows(just in case) */ + asm volatile ("mcr p15, 0, %0, c9, c12, 3" :: "r"(pmcntenset)); +} + +rt_inline unsigned long rt_hw_pmu_get_control(void) +{ + unsigned long pmcr; + asm ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + return pmcr; +} + +rt_inline unsigned long rt_hw_pmu_get_ceid(void) +{ + unsigned long reg; + /* only PMCEID0 is supported, PMCEID1 is RAZ. */ + asm ("mrc p15, 0, %0, c9, c12, 6" : "=r"(reg)); + return reg; +} + +rt_inline unsigned long rt_hw_pmu_get_cnten(void) +{ + unsigned long pmcnt; + asm ("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcnt)); + return pmcnt; +} + +rt_inline void rt_hw_pmu_reset_cycle(void) +{ + unsigned long pmcr; + + asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + pmcr |= ARM_PMU_PMCR_C; + asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr)); + asm volatile ("isb"); +} + +rt_inline void rt_hw_pmu_reset_event(void) +{ + unsigned long pmcr; + + asm volatile ("mrc p15, 0, %0, c9, c12, 0" : "=r"(pmcr)); + pmcr |= ARM_PMU_PMCR_P; + asm volatile ("mcr p15, 0, %0, c9, c12, 0" :: "r"(pmcr)); + asm volatile ("isb"); +} + +rt_inline unsigned long rt_hw_pmu_get_cycle(void) +{ + unsigned long cyc; + asm volatile ("isb"); + asm volatile ("mrc p15, 0, %0, c9, c13, 0" : "=r"(cyc)); + return cyc; +} + +rt_inline void rt_hw_pmu_select_counter(int idx) +{ + RT_ASSERT(idx < ARM_PMU_CNTER_NR); + + asm volatile ("mcr p15, 0, %0, c9, c12, 5" : : "r"(idx)); + /* Linux add an isb here, don't know why here. */ + asm volatile ("isb"); +} + +rt_inline void rt_hw_pmu_select_event(int idx, + enum rt_hw_pmu_event_type eve) +{ + RT_ASSERT(idx < ARM_PMU_CNTER_NR); + + rt_hw_pmu_select_counter(idx); + asm volatile ("mcr p15, 0, %0, c9, c13, 1" : : "r"(eve)); +} + +rt_inline unsigned long rt_hw_pmu_read_counter(int idx) +{ + unsigned long reg; + + rt_hw_pmu_select_counter(idx); + asm volatile ("isb"); + asm volatile ("mrc p15, 0, %0, c9, c13, 2" : "=r"(reg)); + return reg; +} + +rt_inline unsigned long rt_hw_pmu_get_ovsr(void) +{ + unsigned long reg; + asm volatile ("isb"); + asm ("mrc p15, 0, %0, c9, c12, 3" : "=r"(reg)); + return reg; +} + +rt_inline void rt_hw_pmu_clear_ovsr(unsigned long reg) +{ + asm ("mcr p15, 0, %0, c9, c12, 3" : : "r"(reg)); + asm volatile ("isb"); +} + +#endif + +void rt_hw_pmu_dump_feature(void); + +#endif /* end of include guard: __PMU_H__ */ + diff --git a/libcpu/arm/realview-a8-vmm/stack.c b/libcpu/arm/realview-a8-vmm/stack.c new file mode 100644 index 0000000000..4ae1536a20 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/stack.c @@ -0,0 +1,65 @@ +/* + * File : stack.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2011, RT-Thread Development Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2011-09-23 Bernard the first version + * 2011-10-05 Bernard add thumb mode + */ +#include <rtthread.h> +#include <board.h> + +/** + * @addtogroup AM33xx + */ +/*@{*/ + +/** + * This function will initialize thread stack + * + * @param tentry the entry of thread + * @param parameter the parameter of entry + * @param stack_addr the beginning stack address + * @param texit the function will be called when thread exit + * + * @return stack address + */ +rt_uint8_t *rt_hw_stack_init(void *tentry, void *parameter, + rt_uint8_t *stack_addr, void *texit) +{ + rt_uint32_t *stk; + + stk = (rt_uint32_t*)stack_addr; + *(stk) = (rt_uint32_t)tentry; /* entry point */ + *(--stk) = (rt_uint32_t)texit; /* lr */ + *(--stk) = 0; /* r12 */ + *(--stk) = 0; /* r11 */ + *(--stk) = 0; /* r10 */ + *(--stk) = 0; /* r9 */ + *(--stk) = 0; /* r8 */ + *(--stk) = 0; /* r7 */ + *(--stk) = 0; /* r6 */ + *(--stk) = 0; /* r5 */ + *(--stk) = 0; /* r4 */ + *(--stk) = 0; /* r3 */ + *(--stk) = 0; /* r2 */ + *(--stk) = 0; /* r1 */ + *(--stk) = (rt_uint32_t)parameter; /* r0 : argument */ + + /* cpsr */ + if ((rt_uint32_t)tentry & 0x01) + *(--stk) = SVCMODE | 0x20; /* thumb mode */ + else + *(--stk) = SVCMODE; /* arm mode */ + + /* return task's current stack address */ + return (rt_uint8_t *)stk; +} + +/*@}*/ diff --git a/libcpu/arm/realview-a8-vmm/start_gcc.S b/libcpu/arm/realview-a8-vmm/start_gcc.S new file mode 100644 index 0000000000..98f22ca1fe --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/start_gcc.S @@ -0,0 +1,366 @@ +/* + * File : start_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013-2014, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ + +#include <rtconfig.h> + +#ifdef RT_USING_VMM +#include <vmm.h> +.equ orig_irq_isr, LINUX_VECTOR_POS+0x18 +#else +#undef RT_VMM_USING_DOMAIN +#endif + +.equ Mode_USR, 0x10 +.equ Mode_FIQ, 0x11 +.equ Mode_IRQ, 0x12 +.equ Mode_SVC, 0x13 +.equ Mode_ABT, 0x17 +.equ Mode_UND, 0x1B +.equ Mode_SYS, 0x1F + +.equ I_Bit, 0x80 @ when I bit is set, IRQ is disabled +.equ F_Bit, 0x40 @ when F bit is set, FIQ is disabled + +#ifndef RT_USING_VMM +.equ UND_Stack_Size, 0x00000000 +.equ SVC_Stack_Size, 0x00000100 +.equ ABT_Stack_Size, 0x00000000 +.equ RT_FIQ_STACK_PGSZ, 0x00000000 +.equ RT_IRQ_STACK_PGSZ, 0x00000100 +.equ USR_Stack_Size, 0x00000100 + +#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \ + RT_FIQ_STACK_PGSZ + RT_IRQ_STACK_PGSZ) +#else +#define ISR_Stack_Size (RT_FIQ_STACK_PGSZ + RT_IRQ_STACK_PGSZ) +#endif + +.section .data.share.isr +/* stack */ +.globl stack_start +.globl stack_top + +stack_start: +.rept ISR_Stack_Size +.byte 0 +.endr +stack_top: + +.text +/* reset entry */ +.globl _reset +_reset: +#ifdef RT_USING_VMM + /* save all the parameter and variable registers */ + stmfd sp!, {r0-r12, lr} +#endif + /* set the cpu to SVC32 mode and disable interrupt */ + mrs r0, cpsr + bic r0, r0, #0x1f + orr r0, r0, #0x13 + msr cpsr_c, r0 + + /* setup stack */ + bl stack_setup + + /* clear .bss */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_start /* bss start */ + ldr r2,=__bss_end /* bss end */ + +bss_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_loop /* loop until done */ + +#ifdef RT_USING_VMM + /* clear .bss.share */ + mov r0,#0 /* get a zero */ + ldr r1,=__bss_share_start /* bss start */ + ldr r2,=__bss_share_end /* bss end */ + +bss_share_loop: + cmp r1,r2 /* check if data to clear */ + strlo r0,[r1],#4 /* clear 4 bytes */ + blo bss_share_loop /* loop until done */ +#endif + + /* call C++ constructors of global objects */ + ldr r0, =__ctors_start__ + ldr r1, =__ctors_end__ + +ctor_loop: + cmp r0, r1 + beq ctor_end + ldr r2, [r0], #4 + stmfd sp!, {r0-r1} + mov lr, pc + bx r2 + ldmfd sp!, {r0-r1} + b ctor_loop +ctor_end: + + /* start RT-Thread Kernel */ +#ifdef RT_USING_VMM + /* restore the parameter */ + ldmfd sp!, {r0-r3} + bl vmm_entry + ldmfd sp!, {r4-r12, pc} +#else + ldr pc, _rtthread_startup +_rtthread_startup: + .word rtthread_startup +#endif + +stack_setup: + ldr r0, =stack_top +#ifdef RT_USING_VMM + @ Linux use stmia to save r0, lr and spsr. To align to 8 byte boundary, + @ just allocate 16 bytes for it. + sub r0, r0, #16 +#endif + +#ifndef RT_USING_VMM + @ Set the startup stack for svc + mov sp, r0 +#endif + +#ifndef RT_USING_VMM + @ Enter Undefined Instruction Mode and set its Stack Pointer + msr cpsr_c, #Mode_UND|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #UND_Stack_Size + + @ Enter Abort Mode and set its Stack Pointer + msr cpsr_c, #Mode_ABT|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #ABT_Stack_Size +#endif + + @ Enter FIQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #RT_FIQ_STACK_PGSZ + + @ Enter IRQ Mode and set its Stack Pointer + msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit + mov sp, r0 + sub r0, r0, #RT_IRQ_STACK_PGSZ + + /* come back to SVC mode */ + msr cpsr_c, #Mode_SVC|I_Bit|F_Bit + bx lr + +/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */ +.section .text.isr, "ax" + .align 5 +.globl vector_fiq +vector_fiq: + stmfd sp!,{r0-r7,lr} + bl rt_hw_trap_fiq + ldmfd sp!,{r0-r7,lr} + subs pc, lr, #4 + +.globl rt_interrupt_enter +.globl rt_interrupt_leave +.globl rt_thread_switch_interrupt_flag +.globl rt_interrupt_from_thread +.globl rt_interrupt_to_thread + +.globl rt_current_thread +.globl vmm_thread +.globl vmm_virq_check + + .align 5 +.globl vector_irq +vector_irq: + stmfd sp!, {r0-r12,lr} + +#ifdef RT_VMM_USING_DOMAIN + @ save the last domain + mrc p15, 0, r5, c3, c0 + @ switch to vmm domain as we are going to call vmm codes + ldr r1, =vmm_domain_val + ldr r4, [r1] + mcr p15, 0, r4, c3, c0 +#endif + + bl rt_interrupt_enter + bl rt_hw_trap_irq + bl rt_interrupt_leave + +#ifdef RT_VMM_USING_DOMAIN + @ restore the last domain. It do some redundant work but simplify the + @ logic. It might be the guest domain so rt_thread_switch_interrupt_flag + @ should lay in .bss.share + mcr p15, 0, r5, c3, c0 +#endif + + @ if rt_thread_switch_interrupt_flag set, jump to + @ rt_hw_context_switch_interrupt_do and don't return + ldr r0, =rt_thread_switch_interrupt_flag + ldr r1, [r0] + cmp r1, #1 + beq rt_hw_context_switch_interrupt_do + +#ifndef RT_USING_VMM + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 +#else +#ifdef RT_VMM_USING_DOMAIN + @ r4 is vmm_domain_val + @ back to vmm domain as we need access rt_current_thread + mcr p15, 0, r4, c3, c0 +#endif + /* check whether we need to do IRQ routing + * ensure the int is disabled. Or there will be an infinite loop. */ + ldr r0, =rt_current_thread + ldr r0, [r0] + ldr r1, =vmm_thread + cmp r0, r1 + beq switch_to_guest + +#ifdef RT_VMM_USING_DOMAIN + @ r5 is domain of interrupted context + @ it might be super_domain_val or vmm_domain_val so we need to restore it. + mcr p15, 0, r5, c3, c0 +#endif + @ switch back if the interrupted thread is not vmm + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + +switch_to_guest: +#ifdef RT_VMM_USING_DOMAIN + @ We are going to execute rt-thread code but accessing the content of the + @ guest. So switch to super domain. + ldr r1, =super_domain_val + ldr r0, [r1] + mcr p15, 0, r0, c3, c0 +#endif + /* check whether there is a pending interrupt for Guest OS */ + bl vmm_virq_check + +#ifdef RT_VMM_USING_DOMAIN + @ All done, restore the guest domain. + mcr p15, 0, r5, c3, c0 +#endif + + cmp r0, #0x0 + beq route_irq_to_guest + + ldmfd sp!, {r0-r12,lr} + subs pc, lr, #4 + +route_irq_to_guest: + ldmfd sp!, {r0-r12,lr} + b orig_irq_isr +#endif /* RT_USING_VMM */ + +rt_hw_context_switch_interrupt_do: + mov r1, #0 @ clear flag + str r1, [r0] + + mov r1, sp @ r1 point to {r0-r3} in stack + add sp, sp, #4*4 + ldmfd sp!, {r4-r12,lr}@ reload saved registers + mrs r0, spsr @ get cpsr of interrupt thread + sub r2, lr, #4 @ save old task's pc to r2 + + @ Switch to SVC mode with no interrupt. If the usr mode guest is + @ interrupted, this will just switch to the stack of kernel space. + @ save the registers in kernel space won't trigger data abort. + msr cpsr_c, #I_Bit|F_Bit|Mode_SVC + + stmfd sp!, {r2} @ push old task's pc + stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4 + ldmfd r1, {r1-r4} @ restore r0-r3 of the interrupt thread + stmfd sp!, {r1-r4} @ push old task's r0-r3 + stmfd sp!, {r0} @ push old task's cpsr + + ldr r4, =rt_interrupt_from_thread + ldr r5, [r4] + str sp, [r5] @ store sp in preempted tasks's TCB + +#ifdef RT_VMM_USING_DOMAIN + @ If a thread is wake up by interrupt, it should be RTT thread. + @ Make sure the domain is correct. + ldr r1, =vmm_domain_val + ldr r2, [r1] + mcr p15, 0, r2, c3, c0 +#endif + ldr r6, =rt_interrupt_to_thread + ldr r6, [r6] + ldr sp, [r6] @ get new task's stack pointer + + ldmfd sp!, {r4} @ pop new task's cpsr to spsr + msr spsr_cxsf, r4 + + ldmfd sp!, {r0-r12,lr,pc}^ @ pop new task's r0-r12,lr & pc, copy spsr to cpsr + +.macro push_svc_reg + sub sp, sp, #17 * 4 @/* Sizeof(struct rt_hw_exp_stack) */ + stmia sp, {r0 - r12} @/* Calling r0-r12 */ + mov r0, sp + mrs r6, spsr @/* Save CPSR */ + str lr, [r0, #15*4] @/* Push PC */ + str r6, [r0, #16*4] @/* Push CPSR */ + cps #Mode_SVC + str sp, [r0, #13*4] @/* Save calling SP */ + str lr, [r0, #14*4] @/* Save calling PC */ +.endm + + .align 5 + .globl vector_swi +vector_swi: + push_svc_reg + bl rt_hw_trap_swi + b . + + .align 5 + .globl vector_undef +vector_undef: + push_svc_reg + bl rt_hw_trap_undef + b . + + .align 5 + .globl vector_pabt +vector_pabt: + push_svc_reg + bl rt_hw_trap_pabt + b . + + .align 5 + .globl vector_dabt +vector_dabt: + push_svc_reg + bl rt_hw_trap_dabt + b . + + .align 5 + .globl vector_resv +vector_resv: + push_svc_reg + bl rt_hw_trap_resv + b . diff --git a/libcpu/arm/realview-a8-vmm/trap.c b/libcpu/arm/realview-a8-vmm/trap.c new file mode 100644 index 0000000000..a6397d20d2 --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/trap.c @@ -0,0 +1,204 @@ +/* + * File : trap.c + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Develop Team + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rt-thread.org/license/LICENSE + * + * Change Logs: + * Date Author Notes + * 2013-07-20 Bernard first version + */ + +#include <rtthread.h> +#include <rthw.h> +#include <board.h> + +#include "armv7.h" + +#ifdef RT_USING_VMM +#include <vmm_context.h> +#endif + +#include "gic.h" + +extern struct rt_thread *rt_current_thread; +#ifdef RT_USING_FINSH +extern long list_thread(void); +#endif + +/** + * this function will show registers of CPU + * + * @param regs the registers point + */ +void rt_hw_show_register(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("Execption:\n"); + rt_kprintf("r00:0x%08x r01:0x%08x r02:0x%08x r03:0x%08x\n", regs->r0, regs->r1, regs->r2, regs->r3); + rt_kprintf("r04:0x%08x r05:0x%08x r06:0x%08x r07:0x%08x\n", regs->r4, regs->r5, regs->r6, regs->r7); + rt_kprintf("r08:0x%08x r09:0x%08x r10:0x%08x\n", regs->r8, regs->r9, regs->r10); + rt_kprintf("fp :0x%08x ip :0x%08x\n", regs->fp, regs->ip); + rt_kprintf("sp :0x%08x lr :0x%08x pc :0x%08x\n", regs->sp, regs->lr, regs->pc); + rt_kprintf("cpsr:0x%08x\n", regs->cpsr); +} + +/** + * When comes across an instruction which it cannot handle, + * it takes the undefined instruction trap. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_undef(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("undefined instruction:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * The software interrupt instruction (SWI) is used for entering + * Supervisor mode, usually to request a particular supervisor + * function. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_swi(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("software interrupt:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during an instruction prefetch. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_pabt(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("prefetch abort:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * An abort indicates that the current memory access cannot be completed, + * which occurs during a data access. + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_dabt(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("data abort:"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +/** + * Normally, system will never reach here + * + * @param regs system registers + * + * @note never invoke this function in application + */ +void rt_hw_trap_resv(struct rt_hw_exp_stack *regs) +{ + rt_kprintf("reserved trap:\n"); + rt_hw_show_register(regs); +#ifdef RT_USING_FINSH + list_thread(); +#endif + rt_hw_cpu_shutdown(); +} + +#define GIC_ACK_INTID_MASK 0x000003ff + +void rt_hw_trap_irq(void) +{ + void *param; + unsigned long ir; + unsigned long fullir; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + + fullir = arm_gic_get_active_irq(0); + ir = fullir & GIC_ACK_INTID_MASK; + + if (ir == 1023) + { + /* Spurious interrupt */ + return; + } + + /* get interrupt service routine */ + isr_func = isr_table[ir].handler; +#ifdef RT_USING_INTERRUPT_INFO + isr_table[ir].counter++; +#endif + if (isr_func) + { + /* Interrupt for myself. */ + param = isr_table[ir].param; + /* turn to interrupt service routine */ + isr_func(ir, param); + } +#ifdef RT_USING_VMM + else + { + /* We have to EOI before masking the interrupts */ + arm_gic_ack(0, fullir); + vmm_virq_pending(ir); + return; + } +#endif + + /* end of interrupt */ + arm_gic_ack(0, fullir); +} + +void rt_hw_trap_fiq(void) +{ + void *param; + unsigned long ir; + unsigned long fullir; + rt_isr_handler_t isr_func; + extern struct rt_irq_desc isr_table[]; + + fullir = arm_gic_get_active_irq(0); + ir = fullir & GIC_ACK_INTID_MASK; + + /* get interrupt service routine */ + isr_func = isr_table[ir].handler; + param = isr_table[ir].param; + + /* turn to interrupt service routine */ + isr_func(ir, param); + + /* end of interrupt */ + arm_gic_ack(0, fullir); +} + diff --git a/libcpu/arm/realview-a8-vmm/vector_gcc.S b/libcpu/arm/realview-a8-vmm/vector_gcc.S new file mode 100644 index 0000000000..8d0ca27fee --- /dev/null +++ b/libcpu/arm/realview-a8-vmm/vector_gcc.S @@ -0,0 +1,66 @@ +/* + * File : vector_gcc.S + * This file is part of RT-Thread RTOS + * COPYRIGHT (C) 2013, RT-Thread Development Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Change Logs: + * Date Author Notes + * 2013-07-05 Bernard the first version + */ +#include <rtconfig.h> + +.section .vectors, "ax" +.code 32 + +.globl system_vectors +system_vectors: + ldr pc, _vector_reset + ldr pc, _vector_undef + ldr pc, _vector_swi + ldr pc, _vector_pabt + ldr pc, _vector_dabt + ldr pc, _vector_resv + ldr pc, _vector_irq + ldr pc, _vector_fiq + +.globl _reset +.globl vector_undef +.globl vector_swi +.globl vector_pabt +.globl vector_dabt +.globl vector_resv +.globl vector_irq +.globl vector_fiq + +_vector_reset: + .word _reset +_vector_undef: + .word vector_undef +_vector_swi: + .word vector_swi +_vector_pabt: + .word vector_pabt +_vector_dabt: + .word vector_dabt +_vector_resv: + .word vector_resv +_vector_irq: + .word vector_irq +_vector_fiq: + .word vector_fiq + +.balignl 16,0xdeadbeef |
