This commit is contained in:
2024-08-05 20:57:09 +08:00
commit 46d9ee7795
3020 changed files with 1725767 additions and 0 deletions

297
rt-thread/libcpu/Kconfig Normal file
View File

@@ -0,0 +1,297 @@
if ARCH_ARMV8 && ARCH_CPU_64BIT
menu "AArch64 Architecture Configuration"
config ARCH_TEXT_OFFSET
hex "Text offset"
default 0x200000
config ARCH_RAM_OFFSET
hex "RAM offset"
default 0
config ARCH_SECONDARY_CPU_STACK_SIZE
int "Secondary CPU stack size"
default 4096
config ARCH_HAVE_EFFICIENT_UNALIGNED_ACCESS
bool
default y
config ARCH_USING_GENERIC_CPUID
bool "Using generic cpuid implemenation"
select ARCH_USING_HW_THREAD_SELF
default y if RT_USING_OFW
default n
config ARCH_HEAP_SIZE
hex "Size of system heap"
default 0x4000000
config ARCH_INIT_PAGE_SIZE
hex "Size of init page region"
default 0x200000
endmenu
endif
config ARCH_CPU_64BIT
bool
config RT_USING_CACHE
bool
default n
config RT_USING_HW_ATOMIC
bool
default n
config ARCH_CPU_BIG_ENDIAN
bool
config ARCH_ARM_BOOTWITH_FLUSH_CACHE
bool
default n
config ARCH_CPU_STACK_GROWS_UPWARD
bool
default n
config RT_USING_CPU_FFS
bool
default n
config ARCH_MM_MMU
bool
config ARCH_MM_MPU
bool
config ARCH_ARM
bool
config ARCH_ARM_CORTEX_M
bool
select ARCH_ARM
config ARCH_ARM_CORTEX_R
bool
select ARCH_ARM
config ARCH_ARM_CORTEX_FPU
bool
config ARCH_ARM_CORTEX_SECURE
bool
config ARCH_ARM_CORTEX_M0
bool
select ARCH_ARM_CORTEX_M
config ARCH_ARM_CORTEX_M3
bool
select ARCH_ARM_CORTEX_M
select RT_USING_CPU_FFS
select RT_USING_HW_ATOMIC
config ARCH_ARM_MPU
bool
depends on ARCH_ARM
select ARCH_MM_MPU
config ARCH_ARM_CORTEX_M4
bool
select ARCH_ARM_CORTEX_M
select RT_USING_CPU_FFS
select RT_USING_HW_ATOMIC
config ARCH_ARM_CORTEX_M7
bool
select ARCH_ARM_CORTEX_M
select RT_USING_CPU_FFS
select RT_USING_CACHE
config ARCH_ARM_CORTEX_M85
bool
select ARCH_ARM_CORTEX_M
select RT_USING_CPU_FFS
select RT_USING_HW_ATOMIC
config ARCH_ARM_CORTEX_M23
bool
select ARCH_ARM_CORTEX_M
select RT_USING_HW_ATOMIC
config ARCH_ARM_CORTEX_M33
bool
select ARCH_ARM_CORTEX_M
select RT_USING_CPU_FFS
select RT_USING_HW_ATOMIC
config ARCH_ARM_CORTEX_R
bool
select ARCH_ARM
select RT_USING_HW_ATOMIC
config ARCH_ARM_CORTEX_R52
bool
select ARCH_ARM_CORTEX_R
config ARCH_ARM_MMU
bool
select RT_USING_CACHE
select ARCH_MM_MMU
depends on ARCH_ARM
if RT_USING_SMART
config KERNEL_VADDR_START
hex "The virtural address of kernel start"
default 0xffff000000000000 if ARCH_ARMV8
default 0xc0000000 if ARCH_ARM
default 0xffffffc000000000 if ARCH_RISCV && ARCH_REMAP_KERNEL
default 0x80000000 if ARCH_RISCV
depends on ARCH_MM_MMU
config RT_IOREMAP_LATE
bool "Support to create IO mapping in the kernel address space after system initlalization."
default n
depends on ARCH_ARM_CORTEX_A
depends on ARCH_MM_MMU
endif
config ARCH_ARM_ARM9
bool
select ARCH_ARM
config ARCH_ARM_ARM11
bool
select ARCH_ARM
config ARCH_ARM_CORTEX_A
bool
select ARCH_ARM
select ARCH_ARM_MMU
select RT_USING_CPU_FFS
select RT_USING_HW_ATOMIC
if ARCH_ARM_CORTEX_A
config RT_SMP_AUTO_BOOT
bool
default n
config RT_USING_GIC_V2
bool
default n
config RT_USING_GIC_V3
bool
default n
config RT_NO_USING_GIC
bool
default y if !RT_USING_GIC_V2 && !RT_USING_GIC_V3
endif
config ARCH_ARM_CORTEX_A5
bool
select ARCH_ARM_CORTEX_A
config ARCH_ARM_CORTEX_A7
bool
select ARCH_ARM_CORTEX_A
config ARCH_ARM_CORTEX_A8
bool
select ARCH_ARM_CORTEX_A
config ARCH_ARM_CORTEX_A9
bool
select ARCH_ARM_CORTEX_A
config ARCH_ARM_CORTEX_A55
bool
select ARCH_ARM_CORTEX_A
config ARCH_ARM_SECURE_MODE
bool "Running in secure mode [ARM Cortex-A]"
default n
depends on ARCH_ARM_CORTEX_A
config RT_BACKTRACE_FUNCTION_NAME
bool "To show function name when backtrace."
default n
depends on ARCH_ARM_CORTEX_A
config ARCH_ARMV8
bool
select ARCH_ARM
select ARCH_ARM_MMU
select RT_USING_CPU_FFS
config ARCH_MIPS
bool
config ARCH_MIPS64
bool
select ARCH_CPU_64BIT
config ARCH_MIPS_XBURST
bool
select ARCH_MIPS
config ARCH_ANDES
bool
config ARCH_CSKY
bool
config ARCH_POWERPC
bool
config ARCH_RISCV
bool
config ARCH_RISCV_FPU
bool
config ARCH_RISCV_FPU_S
select ARCH_RISCV_FPU
bool
config ARCH_RISCV_FPU_D
select ARCH_RISCV_FPU
bool
config ARCH_RISCV32
select ARCH_RISCV
bool
config ARCH_RISCV64
select ARCH_RISCV
select ARCH_CPU_64BIT
bool
config ARCH_REMAP_KERNEL
bool
depends on RT_USING_SMART
help
Remapping kernel image to high virtual address region
config ARCH_USING_ASID
bool
depends on RT_USING_SMART
help
Using ASID support from architecture
config ARCH_IA32
bool
config ARCH_TIDSP
bool
config ARCH_TIDSP_C28X
bool
select ARCH_TIDSP
select ARCH_CPU_STACK_GROWS_UPWARD
config ARCH_HOST_SIMULATOR
bool
config ARCH_CPU_STACK_GROWS_UPWARD
bool
default n
config ARCH_USING_HW_THREAD_SELF
bool
default n

View File

@@ -0,0 +1,15 @@
# RT-Thread building script for bridge
import os
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
group = []
list = os.listdir(cwd)
if rtconfig.ARCH in list:
group = group + SConscript(os.path.join(rtconfig.ARCH, 'SConscript'))
Return('group')

View File

@@ -0,0 +1,293 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-08-23 Bernard first version
*/
#ifndef __AT91SAM7S_H__
#define __AT91SAM7S_H__
#ifdef __cplusplus
extern "C" {
#endif
#define AT91_REG *(volatile unsigned int *) /* Hardware register definition */
/* ========== Register definition for TC0 peripheral ========== */
#define AT91C_TC0_SR (AT91_REG(0xFFFA0020)) /* TC0 Status Register */
#define AT91C_TC0_RC (AT91_REG(0xFFFA001C)) /* TC0 Register C */
#define AT91C_TC0_RB (AT91_REG(0xFFFA0018)) /* TC0 Register B */
#define AT91C_TC0_CCR (AT91_REG(0xFFFA0000)) /* TC0 Channel Control Register */
#define AT91C_TC0_CMR (AT91_REG(0xFFFA0004)) /* TC0 Channel Mode Register (Capture Mode / Waveform Mode) */
#define AT91C_TC0_IER (AT91_REG(0xFFFA0024)) /* TC0 Interrupt Enable Register */
#define AT91C_TC0_RA (AT91_REG(0xFFFA0014)) /* TC0 Register A */
#define AT91C_TC0_IDR (AT91_REG(0xFFFA0028)) /* TC0 Interrupt Disable Register */
#define AT91C_TC0_CV (AT91_REG(0xFFFA0010)) /* TC0 Counter Value */
#define AT91C_TC0_IMR (AT91_REG(0xFFFA002C)) /* TC0 Interrupt Mask Register */
/* ========== Register definition for TC1 peripheral ========== */
#define AT91C_TC1_RB (AT91_REG(0xFFFA0058)) /* TC1 Register B */
#define AT91C_TC1_CCR (AT91_REG(0xFFFA0040)) /* TC1 Channel Control Register */
#define AT91C_TC1_IER (AT91_REG(0xFFFA0064)) /* TC1 Interrupt Enable Register */
#define AT91C_TC1_IDR (AT91_REG(0xFFFA0068)) /* TC1 Interrupt Disable Register */
#define AT91C_TC1_SR (AT91_REG(0xFFFA0060)) /* TC1 Status Register */
#define AT91C_TC1_CMR (AT91_REG(0xFFFA0044)) /* TC1 Channel Mode Register (Capture Mode / Waveform Mode) */
#define AT91C_TC1_RA (AT91_REG(0xFFFA0054)) /* TC1 Register A */
#define AT91C_TC1_RC (AT91_REG(0xFFFA005C)) /* TC1 Register C */
#define AT91C_TC1_IMR (AT91_REG(0xFFFA006C)) /* TC1 Interrupt Mask Register */
#define AT91C_TC1_CV (AT91_REG(0xFFFA0050)) /* TC1 Counter Value */
/* ========== Register definition for TC2 peripheral ========== */
#define AT91C_TC2_CMR (AT91_REG(0xFFFA0084)) /* TC2 Channel Mode Register (Capture Mode / Waveform Mode) */
#define AT91C_TC2_CCR (AT91_REG(0xFFFA0080)) /* TC2 Channel Control Register */
#define AT91C_TC2_CV (AT91_REG(0xFFFA0090)) /* TC2 Counter Value */
#define AT91C_TC2_RA (AT91_REG(0xFFFA0094)) /* TC2 Register A */
#define AT91C_TC2_RB (AT91_REG(0xFFFA0098)) /* TC2 Register B */
#define AT91C_TC2_IDR (AT91_REG(0xFFFA00A8)) /* TC2 Interrupt Disable Register */
#define AT91C_TC2_IMR (AT91_REG(0xFFFA00AC)) /* TC2 Interrupt Mask Register */
#define AT91C_TC2_RC (AT91_REG(0xFFFA009C)) /* TC2 Register C */
#define AT91C_TC2_IER (AT91_REG(0xFFFA00A4)) /* TC2 Interrupt Enable Register */
#define AT91C_TC2_SR (AT91_REG(0xFFFA00A0)) /* TC2 Status Register */
/* ========== Register definition for PITC peripheral ========== */
#define AT91C_PITC_PIVR (AT91_REG(0xFFFFFD38)) /* PITC Period Interval Value Register */
#define AT91C_PITC_PISR (AT91_REG(0xFFFFFD34)) /* PITC Period Interval Status Register */
#define AT91C_PITC_PIIR (AT91_REG(0xFFFFFD3C)) /* PITC Period Interval Image Register */
#define AT91C_PITC_PIMR (AT91_REG(0xFFFFFD30)) /* PITC Period Interval Mode Register */
/* ========== Register definition for UDP peripheral ========== */
#define AT91C_UDP_NUM (AT91_REG(0xFFFB0000)) /* UDP Frame Number Register */
#define AT91C_UDP_STAT (AT91_REG(0xFFFB0004)) /* UDP Global State Register */
#define AT91C_UDP_FADDR (AT91_REG(0xFFFB0008)) /* UDP Function Address Register */
#define AT91C_UDP_IER (AT91_REG(0xFFFB0010)) /* UDP Interrupt Enable Register */
#define AT91C_UDP_IDR (AT91_REG(0xFFFB0014)) /* UDP Interrupt Disable Register */
#define AT91C_UDP_IMR (AT91_REG(0xFFFB0018)) /* UDP Interrupt Mask Register */
#define AT91C_UDP_ISR (AT91_REG(0xFFFB001C)) /* UDP Interrupt Status Register */
#define AT91C_UDP_ICR (AT91_REG(0xFFFB0020)) /* UDP Interrupt Clear Register */
#define AT91C_UDP_RSTEP (AT91_REG(0xFFFB0028)) /* UDP Reset Endpoint Register */
#define AT91C_UDP_CSR0 (AT91_REG(0xFFFB0030)) /* UDP Endpoint Control and Status Register */
#define AT91C_UDP_CSR(n) (*(&AT91C_UDP_CSR0 + n))
#define AT91C_UDP_FDR0 (AT91_REG(0xFFFB0050)) /* UDP Endpoint FIFO Data Register */
#define AT91C_UDP_FDR(n) (*(&AT91C_UDP_FDR0 + n))
#define AT91C_UDP_TXVC (AT91_REG(0xFFFB0074)) /* UDP Transceiver Control Register */
/* ========== Register definition for US0 peripheral ========== */
#define AT91C_US0_CR (AT91_REG(0xFFFC0000)) /* US0 Control Register */
#define AT91C_US0_MR (AT91_REG(0xFFFC0004)) /* US0 Mode Register */
#define AT91C_US0_IER (AT91_REG(0xFFFC0008)) /* US0 Interrupt Enable Register */
#define AT91C_US0_IDR (AT91_REG(0xFFFC000C)) /* US0 Interrupt Disable Register */
#define AT91C_US0_IMR (AT91_REG(0xFFFC0010)) /* US0 Interrupt Mask Register */
#define AT91C_US0_CSR (AT91_REG(0xFFFC0014)) /* US0 Channel Status Register */
#define AT91C_US0_RHR (AT91_REG(0xFFFC0018)) /* US0 Receiver Holding Register */
#define AT91C_US0_THR (AT91_REG(0xFFFC001C)) /* US0 Transmitter Holding Register */
#define AT91C_US0_BRGR (AT91_REG(0xFFFC0020)) /* US0 Baud Rate Generator Register */
#define AT91C_US0_RTOR (AT91_REG(0xFFFC0024)) /* US0 Receiver Time-out Register */
#define AT91C_US0_TTGR (AT91_REG(0xFFFC0028)) /* US0 Transmitter Time-guard Register */
#define AT91C_US0_NER (AT91_REG(0xFFFC0044)) /* US0 Nb Errors Register */
#define AT91C_US0_FIDI (AT91_REG(0xFFFC0040)) /* US0 FI_DI_Ratio Register */
#define AT91C_US0_IF (AT91_REG(0xFFFC004C)) /* US0 IRDA_FILTER Register */
/* ========== Register definition for AIC peripheral ========== */
#define AT91C_AIC_SMR0 (AT91_REG(0xFFFFF000)) /* AIC Source Mode Register */
#define AT91C_AIC_SMR(n) (*(&AT91C_AIC_SMR0 + n))
#define AT91C_AIC_SVR0 (AT91_REG(0xFFFFF080)) /* AIC Source Vector Register */
#define AT91C_AIC_SVR(n) (*(&AT91C_AIC_SVR0 + n))
#define AT91C_AIC_IVR (AT91_REG(0xFFFFF100)) /* AIC Interrupt Vector Register */
#define AT91C_AIC_FVR (AT91_REG(0xFFFFF104)) /* AIC FIQ Vector Register */
#define AT91C_AIC_ISR (AT91_REG(0xFFFFF108)) /* AIC Interrupt Status Register */
#define AT91C_AIC_IPR (AT91_REG(0xFFFFF10C)) /* AIC Interrupt Pending Register */
#define AT91C_AIC_IMR (AT91_REG(0xFFFFF110)) /* AIC Interrupt Mask Register */
#define AT91C_AIC_CISR (AT91_REG(0xFFFFF114)) /* AIC Core Interrupt Status Register */
#define AT91C_AIC_IECR (AT91_REG(0xFFFFF120)) /* AIC Interrupt Enable Command Register */
#define AT91C_AIC_IDCR (AT91_REG(0xFFFFF124)) /* AIC Interrupt Disable Command Register */
#define AT91C_AIC_ICCR (AT91_REG(0xFFFFF128)) /* AIC Interrupt Clear Command Register */
#define AT91C_AIC_ISCR (AT91_REG(0xFFFFF12C)) /* AIC Interrupt Set Command Register */
#define AT91C_AIC_EOICR (AT91_REG(0xFFFFF130)) /* AIC End of Interrupt Command Register */
#define AT91C_AIC_SPU (AT91_REG(0xFFFFF134)) /* AIC Spurious Vector Register */
#define AT91C_AIC_DCR (AT91_REG(0xFFFFF138)) /* AIC Debug Control Register (Protect) */
#define AT91C_AIC_FFER (AT91_REG(0xFFFFF140)) /* AIC Fast Forcing Enable Register */
#define AT91C_AIC_FFDR (AT91_REG(0xFFFFF144)) /* AIC Fast Forcing Disable Register */
#define AT91C_AIC_FFSR (AT91_REG(0xFFFFF148)) /* AIC Fast Forcing Status Register */
/* ========== Register definition for DBGU peripheral ========== */
#define AT91C_DBGU_EXID (AT91_REG(0xFFFFF244)) /* DBGU Chip ID Extension Register */
#define AT91C_DBGU_BRGR (AT91_REG(0xFFFFF220)) /* DBGU Baud Rate Generator Register */
#define AT91C_DBGU_IDR (AT91_REG(0xFFFFF20C)) /* DBGU Interrupt Disable Register */
#define AT91C_DBGU_CSR (AT91_REG(0xFFFFF214)) /* DBGU Channel Status Register */
#define AT91C_DBGU_CIDR (AT91_REG(0xFFFFF240)) /* DBGU Chip ID Register */
#define AT91C_DBGU_MR (AT91_REG(0xFFFFF204)) /* DBGU Mode Register */
#define AT91C_DBGU_IMR (AT91_REG(0xFFFFF210)) /* DBGU Interrupt Mask Register */
#define AT91C_DBGU_CR (AT91_REG(0xFFFFF200)) /* DBGU Control Register */
#define AT91C_DBGU_FNTR (AT91_REG(0xFFFFF248)) /* DBGU Force NTRST Register */
#define AT91C_DBGU_THR (AT91_REG(0xFFFFF21C)) /* DBGU Transmitter Holding Register */
#define AT91C_DBGU_RHR (AT91_REG(0xFFFFF218)) /* DBGU Receiver Holding Register */
#define AT91C_DBGU_IER (AT91_REG(0xFFFFF208)) /* DBGU Interrupt Enable Register */
/* ========== Register definition for PIO peripheral ========== */
#define AT91C_PIO_ODR (AT91_REG(0xFFFFF414)) /* PIOA Output Disable Registerr */
#define AT91C_PIO_SODR (AT91_REG(0xFFFFF430)) /* PIOA Set Output Data Register */
#define AT91C_PIO_ISR (AT91_REG(0xFFFFF44C)) /* PIOA Interrupt Status Register */
#define AT91C_PIO_ABSR (AT91_REG(0xFFFFF478)) /* PIOA AB Select Status Register */
#define AT91C_PIO_IER (AT91_REG(0xFFFFF440)) /* PIOA Interrupt Enable Register */
#define AT91C_PIO_PPUDR (AT91_REG(0xFFFFF460)) /* PIOA Pull-up Disable Register */
#define AT91C_PIO_IMR (AT91_REG(0xFFFFF448)) /* PIOA Interrupt Mask Register */
#define AT91C_PIO_PER (AT91_REG(0xFFFFF400)) /* PIOA PIO Enable Register */
#define AT91C_PIO_IFDR (AT91_REG(0xFFFFF424)) /* PIOA Input Filter Disable Register */
#define AT91C_PIO_OWDR (AT91_REG(0xFFFFF4A4)) /* PIOA Output Write Disable Register */
#define AT91C_PIO_MDSR (AT91_REG(0xFFFFF458)) /* PIOA Multi-driver Status Register */
#define AT91C_PIO_IDR (AT91_REG(0xFFFFF444)) /* PIOA Interrupt Disable Register */
#define AT91C_PIO_ODSR (AT91_REG(0xFFFFF438)) /* PIOA Output Data Status Register */
#define AT91C_PIO_PPUSR (AT91_REG(0xFFFFF468)) /* PIOA Pull-up Status Register */
#define AT91C_PIO_OWSR (AT91_REG(0xFFFFF4A8)) /* PIOA Output Write Status Register */
#define AT91C_PIO_BSR (AT91_REG(0xFFFFF474)) /* PIOA Select B Register */
#define AT91C_PIO_OWER (AT91_REG(0xFFFFF4A0)) /* PIOA Output Write Enable Register */
#define AT91C_PIO_IFER (AT91_REG(0xFFFFF420)) /* PIOA Input Filter Enable Register */
#define AT91C_PIO_PDSR (AT91_REG(0xFFFFF43C)) /* PIOA Pin Data Status Register */
#define AT91C_PIO_PPUER (AT91_REG(0xFFFFF464)) /* PIOA Pull-up Enable Register */
#define AT91C_PIO_OSR (AT91_REG(0xFFFFF418)) /* PIOA Output Status Register */
#define AT91C_PIO_ASR (AT91_REG(0xFFFFF470)) /* PIOA Select A Register */
#define AT91C_PIO_MDDR (AT91_REG(0xFFFFF454)) /* PIOA Multi-driver Disable Register */
#define AT91C_PIO_CODR (AT91_REG(0xFFFFF434)) /* PIOA Clear Output Data Register */
#define AT91C_PIO_MDER (AT91_REG(0xFFFFF450)) /* PIOA Multi-driver Enable Register */
#define AT91C_PIO_PDR (AT91_REG(0xFFFFF404)) /* PIOA PIO Disable Register */
#define AT91C_PIO_IFSR (AT91_REG(0xFFFFF428)) /* PIOA Input Filter Status Register */
#define AT91C_PIO_OER (AT91_REG(0xFFFFF410)) /* PIOA Output Enable Register */
#define AT91C_PIO_PSR (AT91_REG(0xFFFFF408)) /* PIOA PIO Status Register */
// ========== Register definition for PIOA peripheral ==========
#define AT91C_PIOA_IMR (AT91_REG(0xFFFFF448)) // (PIOA) Interrupt Mask Register
#define AT91C_PIOA_IER (AT91_REG(0xFFFFF440)) // (PIOA) Interrupt Enable Register
#define AT91C_PIOA_OWDR (AT91_REG(0xFFFFF4A4)) // (PIOA) Output Write Disable Register
#define AT91C_PIOA_ISR (AT91_REG(0xFFFFF44C)) // (PIOA) Interrupt Status Register
#define AT91C_PIOA_PPUDR (AT91_REG(0xFFFFF460)) // (PIOA) Pull-up Disable Register
#define AT91C_PIOA_MDSR (AT91_REG(0xFFFFF458)) // (PIOA) Multi-driver Status Register
#define AT91C_PIOA_MDER (AT91_REG(0xFFFFF450)) // (PIOA) Multi-driver Enable Register
#define AT91C_PIOA_PER (AT91_REG(0xFFFFF400)) // (PIOA) PIO Enable Register
#define AT91C_PIOA_PSR (AT91_REG(0xFFFFF408)) // (PIOA) PIO Status Register
#define AT91C_PIOA_OER (AT91_REG(0xFFFFF410)) // (PIOA) Output Enable Register
#define AT91C_PIOA_BSR (AT91_REG(0xFFFFF474)) // (PIOA) Select B Register
#define AT91C_PIOA_PPUER (AT91_REG(0xFFFFF464)) // (PIOA) Pull-up Enable Register
#define AT91C_PIOA_MDDR (AT91_REG(0xFFFFF454)) // (PIOA) Multi-driver Disable Register
#define AT91C_PIOA_PDR (AT91_REG(0xFFFFF404)) // (PIOA) PIO Disable Register
#define AT91C_PIOA_ODR (AT91_REG(0xFFFFF414)) // (PIOA) Output Disable Registerr
#define AT91C_PIOA_IFDR (AT91_REG(0xFFFFF424)) // (PIOA) Input Filter Disable Register
#define AT91C_PIOA_ABSR (AT91_REG(0xFFFFF478)) // (PIOA) AB Select Status Register
#define AT91C_PIOA_ASR (AT91_REG(0xFFFFF470)) // (PIOA) Select A Register
#define AT91C_PIOA_PPUSR (AT91_REG(0xFFFFF468)) // (PIOA) Pull-up Status Register
#define AT91C_PIOA_ODSR (AT91_REG(0xFFFFF438)) // (PIOA) Output Data Status Register
#define AT91C_PIOA_SODR (AT91_REG(0xFFFFF430)) // (PIOA) Set Output Data Register
#define AT91C_PIOA_IFSR (AT91_REG(0xFFFFF428)) // (PIOA) Input Filter Status Register
#define AT91C_PIOA_IFER (AT91_REG(0xFFFFF420)) // (PIOA) Input Filter Enable Register
#define AT91C_PIOA_OSR (AT91_REG(0xFFFFF418)) // (PIOA) Output Status Register
#define AT91C_PIOA_IDR (AT91_REG(0xFFFFF444)) // (PIOA) Interrupt Disable Register
#define AT91C_PIOA_PDSR (AT91_REG(0xFFFFF43C)) // (PIOA) Pin Data Status Register
#define AT91C_PIOA_CODR (AT91_REG(0xFFFFF434)) // (PIOA) Clear Output Data Register
#define AT91C_PIOA_OWSR (AT91_REG(0xFFFFF4A8)) // (PIOA) Output Write Status Register
#define AT91C_PIOA_OWER (AT91_REG(0xFFFFF4A0)) // (PIOA) Output Write Enable Register
// ========== Register definition for PIOB peripheral ==========
#define AT91C_PIOB_OWSR (AT91_REG(0xFFFFF6A8)) // (PIOB) Output Write Status Register
#define AT91C_PIOB_PPUSR (AT91_REG(0xFFFFF668)) // (PIOB) Pull-up Status Register
#define AT91C_PIOB_PPUDR (AT91_REG(0xFFFFF660)) // (PIOB) Pull-up Disable Register
#define AT91C_PIOB_MDSR (AT91_REG(0xFFFFF658)) // (PIOB) Multi-driver Status Register
#define AT91C_PIOB_MDER (AT91_REG(0xFFFFF650)) // (PIOB) Multi-driver Enable Register
#define AT91C_PIOB_IMR (AT91_REG(0xFFFFF648)) // (PIOB) Interrupt Mask Register
#define AT91C_PIOB_OSR (AT91_REG(0xFFFFF618)) // (PIOB) Output Status Register
#define AT91C_PIOB_OER (AT91_REG(0xFFFFF610)) // (PIOB) Output Enable Register
#define AT91C_PIOB_PSR (AT91_REG(0xFFFFF608)) // (PIOB) PIO Status Register
#define AT91C_PIOB_PER (AT91_REG(0xFFFFF600)) // (PIOB) PIO Enable Register
#define AT91C_PIOB_BSR (AT91_REG(0xFFFFF674)) // (PIOB) Select B Register
#define AT91C_PIOB_PPUER (AT91_REG(0xFFFFF664)) // (PIOB) Pull-up Enable Register
#define AT91C_PIOB_IFDR (AT91_REG(0xFFFFF624)) // (PIOB) Input Filter Disable Register
#define AT91C_PIOB_ODR (AT91_REG(0xFFFFF614)) // (PIOB) Output Disable Registerr
#define AT91C_PIOB_ABSR (AT91_REG(0xFFFFF678)) // (PIOB) AB Select Status Register
#define AT91C_PIOB_ASR (AT91_REG(0xFFFFF670)) // (PIOB) Select A Register
#define AT91C_PIOB_IFER (AT91_REG(0xFFFFF620)) // (PIOB) Input Filter Enable Register
#define AT91C_PIOB_IFSR (AT91_REG(0xFFFFF628)) // (PIOB) Input Filter Status Register
#define AT91C_PIOB_SODR (AT91_REG(0xFFFFF630)) // (PIOB) Set Output Data Register
#define AT91C_PIOB_ODSR (AT91_REG(0xFFFFF638)) // (PIOB) Output Data Status Register
#define AT91C_PIOB_CODR (AT91_REG(0xFFFFF634)) // (PIOB) Clear Output Data Register
#define AT91C_PIOB_PDSR (AT91_REG(0xFFFFF63C)) // (PIOB) Pin Data Status Register
#define AT91C_PIOB_OWER (AT91_REG(0xFFFFF6A0)) // (PIOB) Output Write Enable Register
#define AT91C_PIOB_IER (AT91_REG(0xFFFFF640)) // (PIOB) Interrupt Enable Register
#define AT91C_PIOB_OWDR (AT91_REG(0xFFFFF6A4)) // (PIOB) Output Write Disable Register
#define AT91C_PIOB_MDDR (AT91_REG(0xFFFFF654)) // (PIOB) Multi-driver Disable Register
#define AT91C_PIOB_ISR (AT91_REG(0xFFFFF64C)) // (PIOB) Interrupt Status Register
#define AT91C_PIOB_IDR (AT91_REG(0xFFFFF644)) // (PIOB) Interrupt Disable Register
#define AT91C_PIOB_PDR (AT91_REG(0xFFFFF604)) // (PIOB) PIO Disable Register
/* ========== Register definition for PMC peripheral ========== */
#define AT91C_PMC_SCER (AT91_REG(0xFFFFFC00)) /* PMC System Clock Enable Register */
#define AT91C_PMC_SCDR (AT91_REG(0xFFFFFC04)) /* PMC System Clock Disable Register */
#define AT91C_PMC_SCSR (AT91_REG(0xFFFFFC08)) /* PMC System Clock Status Register */
#define AT91C_PMC_PCER (AT91_REG(0xFFFFFC10)) /* PMC Peripheral Clock Enable Register */
#define AT91C_PMC_PCDR (AT91_REG(0xFFFFFC14)) /* PMC Peripheral Clock Disable Register */
#define AT91C_PMC_PCSR (AT91_REG(0xFFFFFC18)) /* PMC Peripheral Clock Status Register */
#define AT91C_PMC_MOR (AT91_REG(0xFFFFFC20)) /* PMC Main Oscillator Register */
#define AT91C_PMC_MCFR (AT91_REG(0xFFFFFC24)) /* PMC Main Clock Frequency Register */
#define AT91C_PMC_PLLR (AT91_REG(0xFFFFFC2C)) /* PMC PLL Register */
#define AT91C_PMC_MCKR (AT91_REG(0xFFFFFC30)) /* PMC Master Clock Register */
#define AT91C_PMC_PCKR (AT91_REG(0xFFFFFC40)) /* PMC Programmable Clock Register */
#define AT91C_PMC_IER (AT91_REG(0xFFFFFC60)) /* PMC Interrupt Enable Register */
#define AT91C_PMC_IDR (AT91_REG(0xFFFFFC64)) /* PMC Interrupt Disable Register */
#define AT91C_PMC_SR (AT91_REG(0xFFFFFC68)) /* PMC Status Register */
#define AT91C_PMC_IMR (AT91_REG(0xFFFFFC6C)) /* PMC Interrupt Mask Register */
/******************************************************************************/
/* PERIPHERAL ID DEFINITIONS FOR AT91SAM7S64 */
/******************************************************************************/
#define AT91C_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */
#define AT91C_ID_SYS 1 /* System Peripheral */
#define AT91C_ID_PIOA 2 /* Parallel IO Controller A */
#define AT91C_ID_PIOB 3 /* Parallel IO Controller B */
#define AT91C_ID_ADC 4 /* Analog-to-Digital Converter */
#define AT91C_ID_SPI 5 /* Serial Peripheral Interface */
#define AT91C_ID_US0 6 /* USART 0 */
#define AT91C_ID_US1 7 /* USART 1 */
#define AT91C_ID_SSC 8 /* Serial Synchronous Controller */
#define AT91C_ID_TWI 9 /* Two-Wire Interface */
#define AT91C_ID_PWMC 10 /* PWM Controller */
#define AT91C_ID_UDP 11 /* USB Device Port */
#define AT91C_ID_TC0 12 /* Timer Counter 0 */
#define AT91C_ID_TC1 13 /* Timer Counter 1 */
#define AT91C_ID_TC2 14 /* Timer Counter 2 */
#define AT91C_ID_15 15 /* Reserved */
#define AT91C_ID_16 16 /* Reserved */
#define AT91C_ID_17 17 /* Reserved */
#define AT91C_ID_18 18 /* Reserved */
#define AT91C_ID_19 19 /* Reserved */
#define AT91C_ID_20 20 /* Reserved */
#define AT91C_ID_21 21 /* Reserved */
#define AT91C_ID_22 22 /* Reserved */
#define AT91C_ID_23 23 /* Reserved */
#define AT91C_ID_24 24 /* Reserved */
#define AT91C_ID_25 25 /* Reserved */
#define AT91C_ID_26 26 /* Reserved */
#define AT91C_ID_27 27 /* Reserved */
#define AT91C_ID_28 28 /* Reserved */
#define AT91C_ID_29 29 /* Reserved */
#define AT91C_ID_IRQ0 30 /* Advanced Interrupt Controller (IRQ0) */
#define AT91C_ID_IRQ1 31 /* Advanced Interrupt Controller (IRQ1) */
#define AT91C_ALL_INT 0xC0007FF7 /* ALL VALID INTERRUPTS */
/*****************************/
/* CPU Mode */
/*****************************/
#define USERMODE 0x10
#define FIQMODE 0x11
#define IRQMODE 0x12
#define SVCMODE 0x13
#define ABORTMODE 0x17
#define UNDEFMODE 0x1b
#define MODEMASK 0x1f
#define NOINT 0xc0
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,23 @@
# RT-Thread building script for component
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')
CPPPATH = [cwd]
if rtconfig.PLATFORM in ['armcc', 'armclang']:
src += Glob('*_rvds.S')
if rtconfig.PLATFORM in ['gcc']:
src += Glob('*_init.S')
src += Glob('*_gcc.S')
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@@ -0,0 +1,90 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-03-13 Bernard first version
*/
#define NOINT 0xc0
/*
* rt_base_t rt_hw_interrupt_disable()/*
*/
.globl rt_hw_interrupt_disable
rt_hw_interrupt_disable:
mrs r0, cpsr
orr r1, r0, #NOINT
msr cpsr_c, r1
mov pc, lr
/*
* void rt_hw_interrupt_enable(rt_base_t level)/*
*/
.globl rt_hw_interrupt_enable
rt_hw_interrupt_enable:
msr cpsr, r0
mov pc, lr
/*
* 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
stmfd sp!, {r4} /* push cpsr */
mrs r4, spsr
stmfd sp!, {r4} /* push spsr */
str sp, [r0] /* store sp in preempted tasks TCB */
ldr sp, [r1] /* get new task stack pointer */
ldmfd sp!, {r4} /* pop new task spsr */
msr spsr_cxsf, r4
ldmfd sp!, {r4} /* pop new task cpsr */
msr cpsr_cxsf, r4
ldmfd sp!, {r0-r12, lr, pc} /* pop new task r0-r12, lr & pc */
/*
* 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
ldmfd sp!, {r4} /* pop new task cpsr */
msr cpsr_cxsf, r4
ldmfd sp!, {r0-r12, lr, pc} /* pop new task r0-r12, lr & pc */
/*
* 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
mov r3, #1 /* set rt_thread_switch_interrupt_flag to 1 */
str r3, [r2]
ldr r2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
str r0, [r2]
_reswitch:
ldr r2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
str r1, [r2]
mov pc, lr

View File

@@ -0,0 +1,103 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2009-01-20 Bernard first version
*/
NOINT EQU 0xc0 ; disable interrupt in psr
AREA |.text|, CODE, READONLY, ALIGN=2
ARM
REQUIRE8
PRESERVE8
;/*
; * rt_base_t rt_hw_interrupt_disable();
; */
rt_hw_interrupt_disable PROC
EXPORT rt_hw_interrupt_disable
MRS r0, cpsr
ORR r1, r0, #NOINT
MSR cpsr_c, r1
BX lr
ENDP
;/*
; * void rt_hw_interrupt_enable(rt_base_t level);
; */
rt_hw_interrupt_enable PROC
EXPORT rt_hw_interrupt_enable
MSR cpsr_c, r0
BX lr
ENDP
;/*
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
; * r0 --> from
; * r1 --> to
; */
rt_hw_context_switch PROC
EXPORT 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
STMFD sp!, {r4} ; push cpsr
MRS r4, spsr
STMFD sp!, {r4} ; push spsr
STR sp, [r0] ; store sp in preempted tasks TCB
LDR sp, [r1] ; get new task stack pointer
LDMFD sp!, {r4} ; pop new task spsr
MSR spsr_cxsf, r4
LDMFD sp!, {r4} ; pop new task cpsr
MSR cpsr_cxsf, r4
LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc
ENDP
;/*
; * void rt_hw_context_switch_to(rt_uint32 to);
; * r0 --> to
; */
rt_hw_context_switch_to PROC
EXPORT rt_hw_context_switch_to
LDR sp, [r0] ; get new task stack pointer
LDMFD sp!, {r4} ; pop new task spsr
MSR spsr_cxsf, r4
LDMFD sp!, {r4} ; pop new task cpsr
MSR cpsr_cxsf, r4
LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc
ENDP
;/*
; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
; */
IMPORT rt_thread_switch_interrupt_flag
IMPORT rt_interrupt_from_thread
IMPORT rt_interrupt_to_thread
rt_hw_context_switch_interrupt PROC
EXPORT rt_hw_context_switch_interrupt
LDR r2, =rt_thread_switch_interrupt_flag
LDR r3, [r2]
CMP r3, #1
BEQ _reswitch
MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 1
STR r3, [r2]
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
STR r0, [r2]
_reswitch
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
STR r1, [r2]
BX lr
ENDP
END

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-08-23 Bernard first version
*/
#include <rtthread.h>
#include "AT91SAM7S.h"
/**
* @addtogroup AT91SAM7
*/
/*@{*/
/*@}*/

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-08-23 Bernard first version
*/
#include <rtthread.h>
#include "AT91SAM7S.h"
#define MAX_HANDLERS 32
extern rt_uint32_t rt_interrupt_nest;
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
rt_uint32_t rt_thread_switch_interrupt_flag;
/**
* @addtogroup AT91SAM7
*/
/*@{*/
void rt_hw_interrupt_handler(int vector)
{
rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
}
/**
* This function will initialize hardware interrupt
*/
void rt_hw_interrupt_init()
{
rt_base_t index;
for (index = 0; index < MAX_HANDLERS; index ++)
{
AT91C_AIC_SVR(index) = (rt_uint32_t)rt_hw_interrupt_handler;
}
/* 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)
{
/* disable interrupt */
AT91C_AIC_IDCR = 1 << vector;
/* clear interrupt */
AT91C_AIC_ICCR = 1 << vector;
}
/**
* This function will un-mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_umask(int vector)
{
AT91C_AIC_IECR = 1 << 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
*/
void rt_hw_interrupt_install(int vector, rt_isr_handler_t new_handler, rt_isr_handler_t *old_handler)
{
if(vector >= 0 && vector < MAX_HANDLERS)
{
if (*old_handler != RT_NULL) *old_handler = (rt_isr_handler_t)AT91C_AIC_SVR(vector);
if (new_handler != RT_NULL) AT91C_AIC_SVR(vector) = (rt_uint32_t)new_handler;
}
}
/*@}*/

View File

@@ -0,0 +1,383 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-08-23 Bernard first version
* 2009-05-14 Bernard add RT-THread device interface
*/
#include <rthw.h>
#include <rtthread.h>
#include "AT91SAM7S.h"
#include "serial.h"
/**
* @addtogroup AT91SAM7
*/
/*@{*/
typedef volatile rt_uint32_t REG32;
struct rt_at91serial_hw
{
REG32 US_CR; // Control Register
REG32 US_MR; // Mode Register
REG32 US_IER; // Interrupt Enable Register
REG32 US_IDR; // Interrupt Disable Register
REG32 US_IMR; // Interrupt Mask Register
REG32 US_CSR; // Channel Status Register
REG32 US_RHR; // Receiver Holding Register
REG32 US_THR; // Transmitter Holding Register
REG32 US_BRGR; // Baud Rate Generator Register
REG32 US_RTOR; // Receiver Time-out Register
REG32 US_TTGR; // Transmitter Time-guard Register
REG32 Reserved0[5]; //
REG32 US_FIDI; // FI_DI_Ratio Register
REG32 US_NER; // Nb Errors Register
REG32 Reserved1[1]; //
REG32 US_IF; // IRDA_FILTER Register
REG32 Reserved2[44]; //
REG32 US_RPR; // Receive Pointer Register
REG32 US_RCR; // Receive Counter Register
REG32 US_TPR; // Transmit Pointer Register
REG32 US_TCR; // Transmit Counter Register
REG32 US_RNPR; // Receive Next Pointer Register
REG32 US_RNCR; // Receive Next Counter Register
REG32 US_TNPR; // Transmit Next Pointer Register
REG32 US_TNCR; // Transmit Next Counter Register
REG32 US_PTCR; // PDC Transfer Control Register
REG32 US_PTSR; // PDC Transfer Status Register
};
struct rt_at91serial
{
struct rt_device parent;
struct rt_at91serial_hw* hw_base;
rt_uint16_t peripheral_id;
rt_uint32_t baudrate;
/* reception field */
rt_uint16_t save_index, read_index;
rt_uint8_t rx_buffer[RT_UART_RX_BUFFER_SIZE];
};
#ifdef RT_USING_UART1
struct rt_at91serial serial1;
#endif
#ifdef RT_USING_UART2
struct rt_at91serial serial2;
#endif
static void rt_hw_serial_isr(int irqno)
{
rt_base_t level;
struct rt_device* device;
struct rt_at91serial* serial = RT_NULL;
if (irqno == AT91C_ID_US0)
{
#ifdef RT_USING_UART1
/* serial 1 */
serial = &serial1;
#endif
}
else if (irqno == AT91C_ID_US1)
{
#ifdef RT_USING_UART2
/* serial 2 */
serial = &serial2;
#endif
}
RT_ASSERT(serial != RT_NULL);
/* get generic device object */
device = (rt_device_t)serial;
/* disable interrupt */
level = rt_hw_interrupt_disable();
/* get received character */
serial->rx_buffer[serial->save_index] = serial->hw_base->US_RHR;
/* move to next position */
serial->save_index ++;
if (serial->save_index >= RT_UART_RX_BUFFER_SIZE)
serial->save_index = 0;
/* if the next position is read index, discard this 'read char' */
if (serial->save_index == serial->read_index)
{
serial->read_index ++;
if (serial->read_index >= RT_UART_RX_BUFFER_SIZE)
serial->read_index = 0;
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
/* indicate to upper layer application */
if (device->rx_indicate != RT_NULL)
device->rx_indicate(device, 1);
/* ack interrupt */
AT91C_AIC_EOICR = 1;
}
static rt_err_t rt_serial_init (rt_device_t dev)
{
rt_uint32_t bd;
struct rt_at91serial* serial = (struct rt_at91serial*) dev;
RT_ASSERT(serial != RT_NULL);
/* must be US0 or US1 */
RT_ASSERT(((serial->peripheral_id == AT91C_ID_US0) ||
(serial->peripheral_id == AT91C_ID_US1)));
/* Enable Clock for USART */
AT91C_PMC_PCER = 1 << serial->peripheral_id;
/* Enable RxD0 and TxDO Pin */
if (serial->peripheral_id == AT91C_ID_US0)
{
/* set pinmux */
AT91C_PIO_PDR = (1 << 5) | (1 << 6);
}
else if (serial->peripheral_id == AT91C_ID_US1)
{
/* set pinmux */
AT91C_PIO_PDR = (1 << 21) | (1 << 22);
}
serial->hw_base->US_CR = AT91C_US_RSTRX | /* Reset Receiver */
AT91C_US_RSTTX | /* Reset Transmitter */
AT91C_US_RXDIS | /* Receiver Disable */
AT91C_US_TXDIS; /* Transmitter Disable */
serial->hw_base->US_MR = AT91C_US_USMODE_NORMAL | /* Normal Mode */
AT91C_US_CLKS_CLOCK | /* Clock = MCK */
AT91C_US_CHRL_8_BITS | /* 8-bit Data */
AT91C_US_PAR_NONE | /* No Parity */
AT91C_US_NBSTOP_1_BIT; /* 1 Stop Bit */
/* set baud rate divisor */
bd = ((MCK*10)/(serial->baudrate * 16));
if ((bd % 10) >= 5) bd = (bd / 10) + 1;
else bd /= 10;
serial->hw_base->US_BRGR = bd;
serial->hw_base->US_CR = AT91C_US_RXEN | /* Receiver Enable */
AT91C_US_TXEN; /* Transmitter Enable */
/* reset rx index */
serial->save_index = 0;
serial->read_index = 0;
/* reset rx buffer */
rt_memset(serial->rx_buffer, 0, RT_UART_RX_BUFFER_SIZE);
return RT_EOK;
}
static rt_err_t rt_serial_open(rt_device_t dev, rt_uint16_t oflag)
{
struct rt_at91serial *serial = (struct rt_at91serial*)dev;
RT_ASSERT(serial != RT_NULL);
if (dev->flag & RT_DEVICE_FLAG_INT_RX)
{
/* enable UART rx interrupt */
serial->hw_base->US_IER = 1 << 0; /* RxReady interrupt */
serial->hw_base->US_IMR |= 1 << 0; /* umask RxReady interrupt */
/* install UART handler */
rt_hw_interrupt_install(serial->peripheral_id, rt_hw_serial_isr, RT_NULL);
AT91C_AIC_SMR(serial->peripheral_id) = 5 | (0x01 << 5);
rt_hw_interrupt_umask(serial->peripheral_id);
}
return RT_EOK;
}
static rt_err_t rt_serial_close(rt_device_t dev)
{
struct rt_at91serial *serial = (struct rt_at91serial*)dev;
RT_ASSERT(serial != RT_NULL);
if (dev->flag & RT_DEVICE_FLAG_INT_RX)
{
/* disable interrupt */
serial->hw_base->US_IDR = 1 << 0; /* RxReady interrupt */
serial->hw_base->US_IMR &= ~(1 << 0); /* mask RxReady interrupt */
}
return RT_EOK;
}
static rt_ssize_t rt_serial_read (rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
{
rt_uint8_t* ptr;
struct rt_at91serial *serial = (struct rt_at91serial*)dev;
RT_ASSERT(serial != RT_NULL);
/* point to buffer */
ptr = (rt_uint8_t*) buffer;
if (dev->flag & RT_DEVICE_FLAG_INT_RX)
{
while (size)
{
/* interrupt receive */
rt_base_t level;
/* disable interrupt */
level = rt_hw_interrupt_disable();
if (serial->read_index != serial->save_index)
{
*ptr = serial->rx_buffer[serial->read_index];
serial->read_index ++;
if (serial->read_index >= RT_UART_RX_BUFFER_SIZE)
serial->read_index = 0;
}
else
{
/* no data in rx buffer */
/* enable interrupt */
rt_hw_interrupt_enable(level);
break;
}
/* enable interrupt */
rt_hw_interrupt_enable(level);
ptr ++; size --;
}
return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
}
else if (dev->flag & RT_DEVICE_FLAG_DMA_RX)
{
/* not support right now */
RT_ASSERT(0);
}
else
{
/* poll mode */
while (size)
{
/* Wait for Full Rx Buffer */
while (!(serial->hw_base->US_CSR & AT91C_US_RXRDY));
/* Read Character */
*ptr = serial->hw_base->US_RHR;
ptr ++;
size --;
}
return (rt_size_t)ptr - (rt_size_t)buffer;
}
return 0;
}
static rt_ssize_t rt_serial_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
{
rt_uint8_t* ptr;
struct rt_at91serial *serial = (struct rt_at91serial*)dev;
RT_ASSERT(serial != RT_NULL);
ptr = (rt_uint8_t*) buffer;
if (dev->open_flag & RT_DEVICE_OFLAG_WRONLY)
{
if (dev->flag & RT_DEVICE_FLAG_STREAM)
{
/* it's a stream mode device */
while (size)
{
/* stream mode */
if (*ptr == '\n')
{
while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY));
serial->hw_base->US_THR = '\r';
}
/* Wait for Empty Tx Buffer */
while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY));
/* Transmit Character */
serial->hw_base->US_THR = *ptr;
ptr ++; size --;
}
}
else
{
while (size)
{
/* Wait for Empty Tx Buffer */
while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY));
/* Transmit Character */
serial->hw_base->US_THR = *ptr;
ptr ++; size --;
}
}
}
return (rt_size_t)ptr - (rt_size_t)buffer;
}
static rt_err_t rt_serial_control (rt_device_t dev, int cmd, void *args)
{
return RT_EOK;
}
rt_err_t rt_hw_serial_init()
{
rt_device_t device;
#ifdef RT_USING_UART1
device = (rt_device_t) &serial1;
/* init serial device private data */
serial1.hw_base = (struct rt_at91serial_hw*)AT91C_BASE_US0;
serial1.peripheral_id = AT91C_ID_US0;
serial1.baudrate = 115200;
/* set device virtual interface */
device->init = rt_serial_init;
device->open = rt_serial_open;
device->close = rt_serial_close;
device->read = rt_serial_read;
device->write = rt_serial_write;
device->control = rt_serial_control;
/* register uart1 on device subsystem */
rt_device_register(device, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
#endif
#ifdef RT_USING_UART2
device = (rt_device_t) &serial2;
serial2.hw_base = (struct rt_at91serial_hw*)AT91C_BASE_US1;
serial2.peripheral_id = AT91C_ID_US1;
serial2.baudrate = 115200;
/* set device virtual interface */
device->init = rt_serial_init;
device->open = rt_serial_open;
device->close = rt_serial_close;
device->read = rt_serial_read;
device->write = rt_serial_write;
device->control = rt_serial_control;
/* register uart2 on device subsystem */
rt_device_register(device, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
#endif
return RT_EOK;
}
/*@}*/

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef __RT_SERIAL_H__
#define __RT_SERIAL_H__
#ifndef AT91C_BASE_US0
#define AT91C_BASE_US0 (0xFFFC0000) // (US0) Base Address
#endif
#ifndef AT91C_BASE_US1
#define AT91C_BASE_US1 (0xFFFC4000) // (US1) Base Address
#endif
#define AT91C_US_RXRDY ((unsigned int) 0x1 << 0) /* US RXRDY Interrupt */
#define AT91C_US_TXRDY ((unsigned int) 0x1 << 1) /* US TXRDY Interrupt */
#define AT91C_US_RSTRX ((unsigned int) 0x1 << 2) /* US Reset Receiver */
#define AT91C_US_RSTTX ((unsigned int) 0x1 << 3) /* US Reset Transmitter */
#define AT91C_US_RXEN ((unsigned int) 0x1 << 4) /* US Receiver Enable */
#define AT91C_US_RXDIS ((unsigned int) 0x1 << 5) /* US Receiver Disable */
#define AT91C_US_TXEN ((unsigned int) 0x1 << 6) /* US Transmitter Enable */
#define AT91C_US_TXDIS ((unsigned int) 0x1 << 7) /* US Transmitter Disable */
#define AT91C_US_RSTSTA ((unsigned int) 0x1 << 8) /* US Reset Status Bits */
#define AT91C_US_USMODE_NORMAL ((unsigned int) 0x0) /* USAR) Normal */
#define AT91C_US_USMODE_RS485 ((unsigned int) 0x1) /* USAR) RS485 */
#define AT91C_US_USMODE_HWHSH ((unsigned int) 0x2) /* USAR) Hardware Handshaking */
#define AT91C_US_USMODE_MODEM ((unsigned int) 0x3) /* USAR) Modem */
#define AT91C_US_USMODE_ISO7816_0 ((unsigned int) 0x4) /* USAR) ISO7816 protocol: T = 0 */
#define AT91C_US_USMODE_ISO7816_1 ((unsigned int) 0x6) /* USAR) ISO7816 protocol: T = 1 */
#define AT91C_US_USMODE_IRDA ((unsigned int) 0x8) /* USAR) IrDA */
#define AT91C_US_USMODE_SWHSH ((unsigned int) 0xC) /* USAR) Software Handshaking */
#define AT91C_US_CLKS_CLOCK ((unsigned int) 0x0 << 4) /* USAR) Clock */
#define AT91C_US_CLKS_FDIV1 ((unsigned int) 0x1 << 4) /* USAR) fdiv1 */
#define AT91C_US_CLKS_SLOW ((unsigned int) 0x2 << 4) /* USAR) slow_clock (ARM) */
#define AT91C_US_CLKS_EXT ((unsigned int) 0x3 << 4) /* USAR) External (SCK) */
#define AT91C_US_CHRL_5_BITS ((unsigned int) 0x0 << 6) /* USAR) Character Length: 5 bits */
#define AT91C_US_CHRL_6_BITS ((unsigned int) 0x1 << 6) /* USAR) Character Length: 6 bits */
#define AT91C_US_CHRL_7_BITS ((unsigned int) 0x2 << 6) /* USAR) Character Length: 7 bits */
#define AT91C_US_CHRL_8_BITS ((unsigned int) 0x3 << 6) /* USAR) Character Length: 8 bits */
#define AT91C_US_PAR_EVEN ((unsigned int) 0x0 << 9) /* DBGU Even Parity */
#define AT91C_US_PAR_ODD ((unsigned int) 0x1 << 9) /* DBGU Odd Parity */
#define AT91C_US_PAR_SPACE ((unsigned int) 0x2 << 9) /* DBGU Parity forced to 0 (Space) */
#define AT91C_US_PAR_MARK ((unsigned int) 0x3 << 9) /* DBGU Parity forced to 1 (Mark) */
#define AT91C_US_PAR_NONE ((unsigned int) 0x4 << 9) /* DBGU No Parity */
#define AT91C_US_PAR_MULTI_DROP ((unsigned int) 0x6 << 9) /* DBGU Multi-drop mode */
#define AT91C_US_NBSTOP_1_BIT ((unsigned int) 0x0 << 12) /* USART 1 stop bit */
#define AT91C_US_NBSTOP_15_BIT ((unsigned int) 0x1 << 12) /* USART Asynchronous (SYNC=0) 2 stop bits Synchronous (SYNC=1) 2 stop bits */
#define AT91C_US_NBSTOP_2_BIT ((unsigned int) 0x2 << 12) /* USART 2 stop bits */
#define MCK 48054857
#define BR 115200 /* Baud Rate */
#define BRD (MCK/16/BR) /* Baud Rate Divisor */
#endif

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-08-23 Bernard the first version
*/
#include <rtthread.h>
#include "AT91SAM7S.h"
/**
* @addtogroup AT91SAM7
*/
/*@{*/
/**
* 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;
stack_addr += sizeof(rt_uint32_t);
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
stk = (rt_uint32_t *)stack_addr;
*(--stk) = (rt_uint32_t)tentry; /* entry point */
*(--stk) = (rt_uint32_t)texit; /* lr */
*(--stk) = 0xdeadbeef; /* r12 */
*(--stk) = 0xdeadbeef; /* r11 */
*(--stk) = 0xdeadbeef; /* r10 */
*(--stk) = 0xdeadbeef; /* r9 */
*(--stk) = 0xdeadbeef; /* r8 */
*(--stk) = 0xdeadbeef; /* r7 */
*(--stk) = 0xdeadbeef; /* r6 */
*(--stk) = 0xdeadbeef; /* r5 */
*(--stk) = 0xdeadbeef; /* r4 */
*(--stk) = 0xdeadbeef; /* r3 */
*(--stk) = 0xdeadbeef; /* r2 */
*(--stk) = 0xdeadbeef; /* r1 */
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
*(--stk) = SVCMODE; /* cpsr */
*(--stk) = SVCMODE; /* spsr */
/* return task's current stack address */
return (rt_uint8_t *)stk;
}
/*@}*/

View File

@@ -0,0 +1,233 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-08-31 Bernard first version
*/
/* Internal Memory Base Addresses */
.equ FLASH_BASE, 0x00100000
.equ RAM_BASE, 0x00200000
/* Stack Configuration */
.equ TOP_STACK, 0x00204000
.equ UND_STACK_SIZE, 0x00000100
.equ SVC_STACK_SIZE, 0x00000400
.equ ABT_STACK_SIZE, 0x00000100
.equ FIQ_STACK_SIZE, 0x00000100
.equ IRQ_STACK_SIZE, 0x00000100
.equ USR_STACK_SIZE, 0x00000004
/* ARM architecture definitions */
.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 this bit is set, IRQ is disabled */
.equ F_BIT, 0x40 /* when this bit is set, FIQ is disabled */
.section .init, "ax"
.code 32
.align 0
.globl _start
_start:
b reset
ldr pc, _vector_undef
ldr pc, _vector_swi
ldr pc, _vector_pabt
ldr pc, _vector_dabt
nop /* reserved vector */
ldr pc, _vector_irq
ldr pc, _vector_fiq
_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
/*
* rtthread bss start and end
* which are defined in linker script
*/
.globl _bss_start
_bss_start: .word __bss_start
.globl _bss_end
_bss_end: .word __bss_end
/* the system entry */
reset:
/* disable watchdog */
ldr r0, =0xFFFFFD40
ldr r1, =0x00008000
str r1, [r0, #0x04]
/* enable the main oscillator */
ldr r0, =0xFFFFFC00
ldr r1, =0x00000601
str r1, [r0, #0x20]
/* wait for main oscillator to stabilize */
moscs_loop:
ldr r2, [r0, #0x68]
ands r2, r2, #1
beq moscs_loop
/* set up the PLL */
ldr r1, =0x00191C05
str r1, [r0, #0x2C]
/* wait for PLL to lock */
pll_loop:
ldr r2, [r0, #0x68]
ands r2, r2, #0x04
beq pll_loop
/* select clock */
ldr r1, =0x00000007
str r1, [r0, #0x30]
/* setup stack for each mode */
ldr r0, =TOP_STACK
/* set stack */
/* undefined instruction mode */
msr cpsr_c, #MODE_UND|I_BIT|F_BIT
mov sp, r0
sub r0, r0, #UND_STACK_SIZE
/* abort mode */
msr cpsr_c, #MODE_ABT|I_BIT|F_BIT
mov sp, r0
sub r0, r0, #ABT_STACK_SIZE
/* FIQ mode */
msr cpsr_c, #MODE_FIQ|I_BIT|F_BIT
mov sp, r0
sub r0, r0, #FIQ_STACK_SIZE
/* IRQ mode */
msr cpsr_c, #MODE_IRQ|I_BIT|F_BIT
mov sp, r0
sub r0, r0, #IRQ_STACK_SIZE
/* supervisor mode */
msr cpsr_c, #MODE_SVC
mov sp, r0
#ifdef __FLASH_BUILD__
/* Relocate .data section (Copy from ROM to RAM) */
ldr r1, =_etext
ldr r2, =_data
ldr r3, =_edata
data_loop:
cmp r2, r3
ldrlo r0, [r1], #4
strlo r0, [r2], #4
blo data_loop
#else
/* remap SRAM to 0x0000 */
ldr r0, =0xFFFFFF00
mov r1, #0x01
str r1, [r0]
#endif
/* mask all IRQs */
ldr r1, =0xFFFFF124
ldr r0, =0XFFFFFFFF
str r0, [r1]
/* start RT-Thread Kernel */
ldr pc, _rtthread_startup
_rtthread_startup: .word rtthread_startup
/* exception handlers */
vector_undef: b vector_undef
vector_swi : b vector_swi
vector_pabt : b vector_pabt
vector_dabt : b vector_dabt
vector_resv : b vector_resv
.globl rt_interrupt_enter
.globl rt_interrupt_leave
.globl rt_thread_switch_interrupt_flag
.globl rt_interrupt_from_thread
.globl rt_interrupt_to_thread
vector_irq:
stmfd sp!, {r0-r12,lr}
bl rt_interrupt_enter
bl rt_hw_trap_irq
bl rt_interrupt_leave
/*
* 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
ldmfd sp!, {r0-r12,lr}
subs pc, lr, #4
vector_fiq:
stmfd sp!,{r0-r7,lr}
bl rt_hw_trap_fiq
ldmfd sp!,{r0-r7,lr}
subs pc,lr,#4
/*
* void rt_hw_context_switch_interrupt_do(rt_base_t flag)
*/
rt_hw_context_switch_interrupt_do:
mov r1, #0 /* clear flag */
str r1, [r0]
ldmfd sp!, {r0-r12,lr} /* reload saved registers */
stmfd sp!, {r0-r3} /* save r0-r3 */
mov r1, sp
add sp, sp, #16 /* restore sp */
sub r2, lr, #4 /* save old task's pc to r2 */
mrs r3, spsr /* disable interrupt */
orr r0, r3, #I_BIT|F_BIT
msr spsr_c, r0
ldr r0, =.+8 /* switch to interrupted task's stack */
movs pc, r0
stmfd sp!, {r2} /* push old task's pc */
stmfd sp!, {r4-r12,lr} /* push old task's lr,r12-r4 */
mov r4, r1 /* Special optimised code below */
mov r5, r3
ldmfd r4!, {r0-r3}
stmfd sp!, {r0-r3} /* push old task's r3-r0 */
stmfd sp!, {r5} /* push old task's psr */
mrs r4, spsr
stmfd sp!, {r4} /* push old task's spsr */
ldr r4, =rt_interrupt_from_thread
ldr r5, [r4]
str sp, [r5] /* store sp in preempted tasks's TCB */
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 spsr */
msr SPSR_cxsf, r4
ldmfd sp!, {r4} /* pop new task's psr */
msr CPSR_cxsf, r4
ldmfd sp!, {r0-r12,lr,pc} /* pop new task's r0-r12,lr & pc */

View File

@@ -0,0 +1,499 @@
;/*****************************************************************************/
;/* SAM7.S: Startup file for Atmel AT91SAM7 device series */
;/*****************************************************************************/
;/* <<< Use Configuration Wizard in Context Menu >>> */
;/*****************************************************************************/
;/* This file is part of the uVision/ARM development tools. */
;/* Copyright (c) 2005-2006 Keil Software. All rights reserved. */
;/* This software may only be used under the terms of a valid, current, */
;/* end user licence from KEIL for a compatible version of KEIL software */
;/* development tools. Nothing else gives you the right to use this software. */
;/*****************************************************************************/
;/*
; * The SAM7.S code is executed after CPU Reset. This file may be
; * translated with the following SET symbols. In uVision these SET
; * symbols are entered under Options - ASM - Define.
; *
; * REMAP: when set the startup code remaps exception vectors from
; * on-chip RAM to address 0.
; *
; * RAM_INTVEC: when set the startup code copies exception vectors
; * from on-chip Flash to on-chip RAM.
; */
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
; Internal Memory Base Addresses
FLASH_BASE EQU 0x00100000
RAM_BASE EQU 0x00200000
;// <h> Stack Configuration (Stack Sizes in Bytes)
;// <o0> Undefined Mode <0x0-0xFFFFFFFF:8>
;// <o1> Supervisor Mode <0x0-0xFFFFFFFF:8>
;// <o2> Abort Mode <0x0-0xFFFFFFFF:8>
;// <o3> Fast Interrupt Mode <0x0-0xFFFFFFFF:8>
;// <o4> Interrupt Mode <0x0-0xFFFFFFFF:8>
;// <o5> User/System Mode <0x0-0xFFFFFFFF:8>
;// </h>
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000100
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000100
USR_Stack_Size EQU 0x00000100
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size)
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE USR_Stack_Size
__initial_sp SPACE ISR_Stack_Size
Stack_Top
;// <h> Heap Configuration
;// <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF>
;// </h>
Heap_Size EQU 0x00000000
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
; Reset Controller (RSTC) definitions
RSTC_BASE EQU 0xFFFFFD00 ; RSTC Base Address
RSTC_MR EQU 0x08 ; RSTC_MR Offset
;/*
;// <e> Reset Controller (RSTC)
;// <o1.0> URSTEN: User Reset Enable
;// <i> Enables NRST Pin to generate Reset
;// <o1.8..11> ERSTL: External Reset Length <0-15>
;// <i> External Reset Time in 2^(ERSTL+1) Slow Clock Cycles
;// </e>
;*/
RSTC_SETUP EQU 1
RSTC_MR_Val EQU 0xA5000401
; Embedded Flash Controller (EFC) definitions
EFC_BASE EQU 0xFFFFFF00 ; EFC Base Address
EFC0_FMR EQU 0x60 ; EFC0_FMR Offset
EFC1_FMR EQU 0x70 ; EFC1_FMR Offset
;// <e> Embedded Flash Controller 0 (EFC0)
;// <o1.16..23> FMCN: Flash Microsecond Cycle Number <0-255>
;// <i> Number of Master Clock Cycles in 1us
;// <o1.8..9> FWS: Flash Wait State
;// <0=> Read: 1 cycle / Write: 2 cycles
;// <1=> Read: 2 cycle / Write: 3 cycles
;// <2=> Read: 3 cycle / Write: 4 cycles
;// <3=> Read: 4 cycle / Write: 4 cycles
;// </e>
EFC0_SETUP EQU 1
EFC0_FMR_Val EQU 0x00320100
;// <e> Embedded Flash Controller 1 (EFC1)
;// <o1.16..23> FMCN: Flash Microsecond Cycle Number <0-255>
;// <i> Number of Master Clock Cycles in 1us
;// <o1.8..9> FWS: Flash Wait State
;// <0=> Read: 1 cycle / Write: 2 cycles
;// <1=> Read: 2 cycle / Write: 3 cycles
;// <2=> Read: 3 cycle / Write: 4 cycles
;// <3=> Read: 4 cycle / Write: 4 cycles
;// </e>
EFC1_SETUP EQU 0
EFC1_FMR_Val EQU 0x00320100
; Watchdog Timer (WDT) definitions
WDT_BASE EQU 0xFFFFFD40 ; WDT Base Address
WDT_MR EQU 0x04 ; WDT_MR Offset
;// <e> Watchdog Timer (WDT)
;// <o1.0..11> WDV: Watchdog Counter Value <0-4095>
;// <o1.16..27> WDD: Watchdog Delta Value <0-4095>
;// <o1.12> WDFIEN: Watchdog Fault Interrupt Enable
;// <o1.13> WDRSTEN: Watchdog Reset Enable
;// <o1.14> WDRPROC: Watchdog Reset Processor
;// <o1.28> WDDBGHLT: Watchdog Debug Halt
;// <o1.29> WDIDLEHLT: Watchdog Idle Halt
;// <o1.15> WDDIS: Watchdog Disable
;// </e>
WDT_SETUP EQU 1
WDT_MR_Val EQU 0x00008000
; Power Mangement Controller (PMC) definitions
PMC_BASE EQU 0xFFFFFC00 ; PMC Base Address
PMC_MOR EQU 0x20 ; PMC_MOR Offset
PMC_MCFR EQU 0x24 ; PMC_MCFR Offset
PMC_PLLR EQU 0x2C ; PMC_PLLR Offset
PMC_MCKR EQU 0x30 ; PMC_MCKR Offset
PMC_SR EQU 0x68 ; PMC_SR Offset
PMC_MOSCEN EQU (1<<0) ; Main Oscillator Enable
PMC_OSCBYPASS EQU (1<<1) ; Main Oscillator Bypass
PMC_OSCOUNT EQU (0xFF<<8) ; Main OScillator Start-up Time
PMC_DIV EQU (0xFF<<0) ; PLL Divider
PMC_PLLCOUNT EQU (0x3F<<8) ; PLL Lock Counter
PMC_OUT EQU (0x03<<14) ; PLL Clock Frequency Range
PMC_MUL EQU (0x7FF<<16) ; PLL Multiplier
PMC_USBDIV EQU (0x03<<28) ; USB Clock Divider
PMC_CSS EQU (3<<0) ; Clock Source Selection
PMC_PRES EQU (7<<2) ; Prescaler Selection
PMC_MOSCS EQU (1<<0) ; Main Oscillator Stable
PMC_LOCK EQU (1<<2) ; PLL Lock Status
PMC_MCKRDY EQU (1<<3) ; Master Clock Status
;// <e> Power Mangement Controller (PMC)
;// <h> Main Oscillator
;// <o1.0> MOSCEN: Main Oscillator Enable
;// <o1.1> OSCBYPASS: Oscillator Bypass
;// <o1.8..15> OSCCOUNT: Main Oscillator Startup Time <0-255>
;// </h>
;// <h> Phase Locked Loop (PLL)
;// <o2.0..7> DIV: PLL Divider <0-255>
;// <o2.16..26> MUL: PLL Multiplier <0-2047>
;// <i> PLL Output is multiplied by MUL+1
;// <o2.14..15> OUT: PLL Clock Frequency Range
;// <0=> 80..160MHz <1=> Reserved
;// <2=> 150..220MHz <3=> Reserved
;// <o2.8..13> PLLCOUNT: PLL Lock Counter <0-63>
;// <o2.28..29> USBDIV: USB Clock Divider
;// <0=> None <1=> 2 <2=> 4 <3=> Reserved
;// </h>
;// <o3.0..1> CSS: Clock Source Selection
;// <0=> Slow Clock
;// <1=> Main Clock
;// <2=> Reserved
;// <3=> PLL Clock
;// <o3.2..4> PRES: Prescaler
;// <0=> None
;// <1=> Clock / 2 <2=> Clock / 4
;// <3=> Clock / 8 <4=> Clock / 16
;// <5=> Clock / 32 <6=> Clock / 64
;// <7=> Reserved
;// </e>
PMC_SETUP EQU 1
PMC_MOR_Val EQU 0x00000601
PMC_PLLR_Val EQU 0x00191C05
PMC_MCKR_Val EQU 0x00000007
PRESERVE8
; Area Definition and Entry Point
; Startup Code must be linked first at Address at which it expects to run.
AREA RESET, CODE, READONLY
ARM
; Exception Vectors
; Mapped to Address 0.
; Absolute addressing mode must be used.
; Dummy Handlers are implemented as infinite loops which can be modified.
Vectors LDR PC,Reset_Addr
LDR PC,Undef_Addr
LDR PC,SWI_Addr
LDR PC,PAbt_Addr
LDR PC,DAbt_Addr
NOP ; Reserved Vector
LDR PC,IRQ_Addr
LDR PC,FIQ_Addr
Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0 ; Reserved Address
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B PAbt_Handler
DAbt_Handler B DAbt_Handler
FIQ_Handler B FIQ_Handler
; Reset Handler
EXPORT Reset_Handler
Reset_Handler
; Setup RSTC
IF RSTC_SETUP != 0
LDR R0, =RSTC_BASE
LDR R1, =RSTC_MR_Val
STR R1, [R0, #RSTC_MR]
ENDIF
; Setup EFC0
IF EFC0_SETUP != 0
LDR R0, =EFC_BASE
LDR R1, =EFC0_FMR_Val
STR R1, [R0, #EFC0_FMR]
ENDIF
; Setup EFC1
IF EFC1_SETUP != 0
LDR R0, =EFC_BASE
LDR R1, =EFC1_FMR_Val
STR R1, [R0, #EFC1_FMR]
ENDIF
; Setup WDT
IF WDT_SETUP != 0
LDR R0, =WDT_BASE
LDR R1, =WDT_MR_Val
STR R1, [R0, #WDT_MR]
ENDIF
; Setup PMC
IF PMC_SETUP != 0
LDR R0, =PMC_BASE
; Setup Main Oscillator
LDR R1, =PMC_MOR_Val
STR R1, [R0, #PMC_MOR]
; Wait until Main Oscillator is stablilized
IF (PMC_MOR_Val:AND:PMC_MOSCEN) != 0
MOSCS_Loop LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_MOSCS
BEQ MOSCS_Loop
ENDIF
; Setup the PLL
IF (PMC_PLLR_Val:AND:PMC_MUL) != 0
LDR R1, =PMC_PLLR_Val
STR R1, [R0, #PMC_PLLR]
; Wait until PLL is stabilized
PLL_Loop LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_LOCK
BEQ PLL_Loop
ENDIF
; Select Clock
IF (PMC_MCKR_Val:AND:PMC_CSS) == 1 ; Main Clock Selected
LDR R1, =PMC_MCKR_Val
AND R1, #PMC_CSS
STR R1, [R0, #PMC_MCKR]
WAIT_Rdy1 LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_MCKRDY
BEQ WAIT_Rdy1
LDR R1, =PMC_MCKR_Val
STR R1, [R0, #PMC_MCKR]
WAIT_Rdy2 LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_MCKRDY
BEQ WAIT_Rdy2
ELIF (PMC_MCKR_Val:AND:PMC_CSS) == 3 ; PLL Clock Selected
LDR R1, =PMC_MCKR_Val
AND R1, #PMC_PRES
STR R1, [R0, #PMC_MCKR]
WAIT_Rdy1 LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_MCKRDY
BEQ WAIT_Rdy1
LDR R1, =PMC_MCKR_Val
STR R1, [R0, #PMC_MCKR]
WAIT_Rdy2 LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_MCKRDY
BEQ WAIT_Rdy2
ENDIF ; Select Clock
ENDIF ; PMC_SETUP
; Copy Exception Vectors to Internal RAM
IF :DEF:RAM_INTVEC
ADR R8, Vectors ; Source
LDR R9, =RAM_BASE ; Destination
LDMIA R8!, {R0-R7} ; Load Vectors
STMIA R9!, {R0-R7} ; Store Vectors
LDMIA R8!, {R0-R7} ; Load Handler Addresses
STMIA R9!, {R0-R7} ; Store Handler Addresses
ENDIF
; Remap on-chip RAM to address 0
MC_BASE EQU 0xFFFFFF00 ; MC Base Address
MC_RCR EQU 0x00 ; MC_RCR Offset
IF :DEF:REMAP
LDR R0, =MC_BASE
MOV R1, #1
STR R1, [R0, #MC_RCR] ; Remap
ENDIF
; Setup Stack for each mode
LDR R0, =Stack_Top
; Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #UND_Stack_Size
; Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #ABT_Stack_Size
; Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MOV SP, R0
SUB R0, R0, #SVC_Stack_Size
; Enter User Mode and set its Stack Pointer
; MSR CPSR_c, #Mode_USR
IF :DEF:__MICROLIB
EXPORT __initial_sp
ELSE
; No usr mode stack here.
;MOV SP, R0
;SUB SL, SP, #USR_Stack_Size
ENDIF
; Enter the C code
IMPORT __main
LDR R0, =__main
BX R0
IMPORT rt_interrupt_enter
IMPORT rt_interrupt_leave
IMPORT rt_thread_switch_interrupt_flag
IMPORT rt_interrupt_from_thread
IMPORT rt_interrupt_to_thread
IMPORT rt_hw_trap_irq
IRQ_Handler PROC
EXPORT IRQ_Handler
STMFD sp!, {r0-r12,lr}
BL rt_interrupt_enter
BL rt_hw_trap_irq
BL rt_interrupt_leave
; 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
LDMFD sp!, {r0-r12,lr}
SUBS pc, lr, #4
ENDP
; /*
; * void rt_hw_context_switch_interrupt_do(rt_base_t flag)
; */
rt_hw_context_switch_interrupt_do PROC
EXPORT rt_hw_context_switch_interrupt_do
MOV r1, #0 ; clear flag
STR r1, [r0]
LDMFD sp!, {r0-r12,lr}; reload saved registers
STMFD sp!, {r0-r3} ; save r0-r3
MOV r1, sp
ADD sp, sp, #16 ; restore sp
SUB r2, lr, #4 ; save old task's pc to r2
MRS r3, spsr ; get cpsr of interrupt thread
; switch to SVC mode and no interrupt
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
MOV r4, r1 ; Special optimised code below
MOV r5, r3
LDMFD r4!, {r0-r3}
STMFD sp!, {r0-r3} ; push old task's r3-r0
STMFD sp!, {r5} ; push old task's cpsr
MRS r4, spsr
STMFD sp!, {r4} ; push old task's spsr
LDR r4, =rt_interrupt_from_thread
LDR r5, [r4]
STR sp, [r5] ; store sp in preempted tasks's TCB
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 spsr
MSR spsr_cxsf, r4
LDMFD sp!, {r4} ; pop new task's psr
MSR cpsr_cxsf, r4
LDMFD sp!, {r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc
ENDP
IF :DEF:__MICROLIB
EXPORT __heap_base
EXPORT __heap_limit
ELSE
; User Initial Stack & Heap
AREA |.text|, CODE, READONLY
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem
LDR R1, = (Stack_Mem + IRQ_Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ENDIF
END

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-08-25 Bernard first version
*/
#include <rtthread.h>
#include <rthw.h>
#include "AT91SAM7S.h"
/**
* @addtogroup AT91SAM7
*/
/*@{*/
void rt_hw_trap_irq()
{
rt_isr_handler_t hander = (rt_isr_handler_t)AT91C_AIC_IVR;
hander(AT91C_AIC_ISR);
/* end of interrupt */
AT91C_AIC_EOICR = 0;
}
void rt_hw_trap_fiq()
{
rt_kprintf("fast interrupt request\n");
}
/*@}*/

View File

@@ -0,0 +1,23 @@
# RT-Thread building script for component
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')
CPPPATH = [cwd]
if rtconfig.PLATFORM in ['armcc', 'armclang']:
src += Glob('*_rvds.S')
if rtconfig.PLATFORM in ['gcc']:
src += Glob('*_init.S')
src += Glob('*_gcc.S')
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@@ -0,0 +1,95 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-03-13 Bernard first version
*/
/*!
* \addtogroup xgs3c4510
*/
/*@{*/
#define NOINT 0xc0
/*
* rt_base_t rt_hw_interrupt_disable();
*/
.globl rt_hw_interrupt_disable
rt_hw_interrupt_disable:
mrs r0, cpsr
orr r1, r0, #NOINT
msr cpsr_c, r1
mov pc, lr
/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
.globl rt_hw_interrupt_enable
rt_hw_interrupt_enable:
msr cpsr, r0
mov pc, lr
/*
* 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
stmfd sp!, {r4} @ push cpsr
mrs r4, spsr
stmfd sp!, {r4} @ push spsr
str sp, [r0] @ store sp in preempted tasks TCB
ldr sp, [r1] @ get new task stack pointer
ldmfd sp!, {r4} @ pop new task spsr
msr spsr_cxsf, r4
ldmfd sp!, {r4} @ pop new task cpsr
msr cpsr_cxsf, r4
ldmfd sp!, {r0-r12, lr, pc} @ pop new task r0-r12, lr & pc
/*
* 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
ldmfd sp!, {r4} @ pop new task cpsr
msr cpsr_cxsf, r4
ldmfd sp!, {r0-r12, lr, pc} @ pop new task r0-r12, lr & pc
/*
* 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
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
str r3, [r2]
ldr r2, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
str r0, [r2]
_reswitch:
ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
str r1, [r2]
mov pc, lr

View File

@@ -0,0 +1,103 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2009-01-20 Bernard first version
*/
NOINT EQU 0xc0 ; disable interrupt in psr
AREA |.text|, CODE, READONLY, ALIGN=2
ARM
REQUIRE8
PRESERVE8
;/*
; * rt_base_t rt_hw_interrupt_disable();
; */
rt_hw_interrupt_disable PROC
EXPORT rt_hw_interrupt_disable
MRS r0, cpsr
ORR r1, r0, #NOINT
MSR cpsr_c, r1
BX lr
ENDP
;/*
; * void rt_hw_interrupt_enable(rt_base_t level);
; */
rt_hw_interrupt_enable PROC
EXPORT rt_hw_interrupt_enable
MSR cpsr_c, r0
BX lr
ENDP
;/*
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
; * r0 --> from
; * r1 --> to
; */
rt_hw_context_switch PROC
EXPORT 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
STMFD sp!, {r4} ; push cpsr
MRS r4, spsr
STMFD sp!, {r4} ; push spsr
STR sp, [r0] ; store sp in preempted tasks TCB
LDR sp, [r1] ; get new task stack pointer
LDMFD sp!, {r4} ; pop new task spsr
MSR spsr_cxsf, r4
LDMFD sp!, {r4} ; pop new task cpsr
MSR cpsr_cxsf, r4
LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc
ENDP
;/*
; * void rt_hw_context_switch_to(rt_uint32 to);
; * r0 --> to
; */
rt_hw_context_switch_to PROC
EXPORT rt_hw_context_switch_to
LDR sp, [r0] ; get new task stack pointer
LDMFD sp!, {r4} ; pop new task spsr
MSR spsr_cxsf, r4
LDMFD sp!, {r4} ; pop new task cpsr
MSR cpsr_cxsf, r4
LDMFD sp!, {r0-r12, lr, pc} ; pop new task r0-r12, lr & pc
ENDP
;/*
; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
; */
IMPORT rt_thread_switch_interrupt_flag
IMPORT rt_interrupt_from_thread
IMPORT rt_interrupt_to_thread
rt_hw_context_switch_interrupt PROC
EXPORT rt_hw_context_switch_interrupt
LDR r2, =rt_thread_switch_interrupt_flag
LDR r3, [r2]
CMP r3, #1
BEQ _reswitch
MOV r3, #1 ; set rt_thread_switch_interrupt_flag to 1
STR r3, [r2]
LDR r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
STR r0, [r2]
_reswitch
LDR r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
STR r1, [r2]
BX lr
ENDP
END

View File

@@ -0,0 +1,20 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-08-23 Bernard first version
*/
#include <rtthread.h>
/**
* @addtogroup AT91SAM7X
*/
/*@{*/
/*@}*/

View File

@@ -0,0 +1,110 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-08-23 Bernard first version
* 2013-03-29 aozima Modify the interrupt interface implementations.
*/
#include <rtthread.h>
#include <rthw.h>
#include "AT91SAM7X256.h"
#define MAX_HANDLERS 32
/* exception and interrupt handler table */
struct rt_irq_desc irq_desc[MAX_HANDLERS];
extern rt_uint32_t rt_interrupt_nest;
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
rt_uint32_t rt_thread_switch_interrupt_flag;
/**
* @addtogroup AT91SAM7
*/
/*@{*/
static void rt_hw_interrupt_handler(int vector, void *param)
{
rt_kprintf("Unhandled interrupt %d occured!!!\n", vector);
}
/**
* This function will initialize hardware interrupt
*/
void rt_hw_interrupt_init(void)
{
rt_base_t index;
/* init exceptions table */
for(index=0; index < MAX_HANDLERS; index++)
{
irq_desc[index].handler = (rt_isr_handler_t)rt_hw_interrupt_handler;
irq_desc[index].param = RT_NULL;
}
for (index = 0; index < MAX_HANDLERS; index ++)
{
AT91C_BASE_AIC->AIC_SVR[index] = (rt_uint32_t)rt_hw_interrupt_handler;
}
/* 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)
{
/* disable interrupt */
AT91C_BASE_AIC->AIC_IDCR = 1 << vector;
/* clear interrupt */
AT91C_BASE_AIC->AIC_ICCR = 1 << vector;
}
/**
* This function will un-mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_umask(int vector)
{
AT91C_BASE_AIC->AIC_IECR = 1 << vector;
}
/**
* This function will install a interrupt service routine to a interrupt.
* @param vector the interrupt number
* @param handler the interrupt service routine to be installed
* @param param the parameter for interrupt service routine
* @name unused.
*
* @return the old handler
*/
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
void *param, const char *name)
{
rt_isr_handler_t old_handler = RT_NULL;
if(vector >= 0 && vector < MAX_HANDLERS)
{
old_handler = irq_desc[vector].handler;
if (handler != RT_NULL)
{
irq_desc[vector].handler = (rt_isr_handler_t)handler;
irq_desc[vector].param = param;
}
}
return old_handler;
}
/*@}*/

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-08-23 Bernard the first version
*/
#include <rtthread.h>
#define SVCMODE 0x13
/**
* @addtogroup AT91SAM7
*/
/*@{*/
/**
* 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;
stack_addr += sizeof(rt_uint32_t);
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
stk = (rt_uint32_t *)stack_addr;
*(--stk) = (rt_uint32_t)tentry; /* entry point */
*(--stk) = (rt_uint32_t)texit; /* lr */
*(--stk) = 0xdeadbeef; /* r12 */
*(--stk) = 0xdeadbeef; /* r11 */
*(--stk) = 0xdeadbeef; /* r10 */
*(--stk) = 0xdeadbeef; /* r9 */
*(--stk) = 0xdeadbeef; /* r8 */
*(--stk) = 0xdeadbeef; /* r7 */
*(--stk) = 0xdeadbeef; /* r6 */
*(--stk) = 0xdeadbeef; /* r5 */
*(--stk) = 0xdeadbeef; /* r4 */
*(--stk) = 0xdeadbeef; /* r3 */
*(--stk) = 0xdeadbeef; /* r2 */
*(--stk) = 0xdeadbeef; /* r1 */
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument */
*(--stk) = SVCMODE; /* cpsr */
*(--stk) = SVCMODE; /* spsr */
/* return task's current stack address */
return (rt_uint8_t *)stk;
}
/*@}*/

View File

@@ -0,0 +1,275 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-08-31 Bernard first version
*/
/* Internal Memory Base Addresses */
.equ FLASH_BASE, 0x00100000
.equ RAM_BASE, 0x00200000
/* Stack Configuration */
.equ TOP_STACK, 0x00204000
.equ UND_STACK_SIZE, 0x00000100
.equ SVC_STACK_SIZE, 0x00000400
.equ ABT_STACK_SIZE, 0x00000100
.equ FIQ_STACK_SIZE, 0x00000100
.equ IRQ_STACK_SIZE, 0x00000100
.equ USR_STACK_SIZE, 0x00000004
/* ARM architecture definitions */
.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 this bit is set, IRQ is disabled */
.equ F_BIT, 0x40 /* when this bit is set, FIQ is disabled */
.section .init, "ax"
.code 32
.align 0
.globl _start
_start:
b reset
ldr pc, _vector_undef
ldr pc, _vector_swi
ldr pc, _vector_pabt
ldr pc, _vector_dabt
nop /* reserved vector */
ldr pc, _vector_irq
ldr pc, _vector_fiq
_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
/*
* rtthread bss start and end
* which are defined in linker script
*/
.globl _bss_start
_bss_start: .word __bss_start
.globl _bss_end
_bss_end: .word __bss_end
/* the system entry */
reset:
/* disable watchdog */
ldr r0, =0xFFFFFD40
ldr r1, =0x00008000
str r1, [r0, #0x04]
/* enable the main oscillator */
ldr r0, =0xFFFFFC00
ldr r1, =0x00000601
str r1, [r0, #0x20]
/* wait for main oscillator to stabilize */
moscs_loop:
ldr r2, [r0, #0x68]
ands r2, r2, #1
beq moscs_loop
/* set up the PLL */
ldr r1, =0x00191C05
str r1, [r0, #0x2C]
/* wait for PLL to lock */
pll_loop:
ldr r2, [r0, #0x68]
ands r2, r2, #0x04
beq pll_loop
/* select clock */
ldr r1, =0x00000007
str r1, [r0, #0x30]
#ifdef __FLASH_BUILD__
/* copy exception vectors into internal sram */
/*
mov r8, #RAM_BASE
ldr r9, =_start
ldmia r9!, {r0-r7}
stmia r8!, {r0-r7}
ldmia r9!, {r0-r6}
stmia r8!, {r0-r6}
*/
#endif
/* setup stack for each mode */
ldr r0, =TOP_STACK
/* set stack */
/* undefined instruction mode */
msr cpsr_c, #MODE_UND|I_BIT|F_BIT
mov sp, r0
sub r0, r0, #UND_STACK_SIZE
/* abort mode */
msr cpsr_c, #MODE_ABT|I_BIT|F_BIT
mov sp, r0
sub r0, r0, #ABT_STACK_SIZE
/* FIQ mode */
msr cpsr_c, #MODE_FIQ|I_BIT|F_BIT
mov sp, r0
sub r0, r0, #FIQ_STACK_SIZE
/* IRQ mode */
msr cpsr_c, #MODE_IRQ|I_BIT|F_BIT
mov sp, r0
sub r0, r0, #IRQ_STACK_SIZE
/* supervisor mode */
msr cpsr_c, #MODE_SVC|I_BIT|F_BIT
mov sp, r0
/* remap SRAM to 0x0000 */
/*
ldr r0, =0xFFFFFF00
mov r1, #0x01
str r1, [r0]
*/
/* mask all IRQs */
ldr r1, =0xFFFFF124
ldr r0, =0XFFFFFFFF
str r0, [r1]
/* copy .data to SRAM */
ldr r1, =_sidata /* .data start in image */
ldr r2, =_edata /* .data end in image */
ldr r3, =_sdata /* sram data start */
data_loop:
ldr r0, [r1, #0]
str r0, [r3]
add r1, r1, #4
add r3, r3, #4
cmp r3, r2 /* check if data to clear */
blo data_loop /* loop until done */
/* 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 */
/* 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 */
ldr pc, _rtthread_startup
_rtthread_startup: .word rtthread_startup
/* exception handlers */
vector_undef: b vector_undef
vector_swi : b vector_swi
vector_pabt : b vector_pabt
vector_dabt : b vector_dabt
vector_resv : b vector_resv
.globl rt_interrupt_enter
.globl rt_interrupt_leave
.globl rt_thread_switch_interrupt_flag
.globl rt_interrupt_from_thread
.globl rt_interrupt_to_thread
vector_irq:
stmfd sp!, {r0-r12,lr}
bl rt_interrupt_enter
bl rt_hw_trap_irq
bl rt_interrupt_leave
/*
* 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
ldmfd sp!, {r0-r12,lr}
subs pc, lr, #4
vector_fiq:
stmfd sp!,{r0-r7,lr}
bl rt_hw_trap_fiq
ldmfd sp!,{r0-r7,lr}
subs pc,lr,#4
/*
* void rt_hw_context_switch_interrupt_do(rt_base_t flag)
*/
rt_hw_context_switch_interrupt_do:
mov r1, #0 @ clear flag
str r1, [r0]
ldmfd sp!, {r0-r12,lr}@ reload saved registers
stmfd sp!, {r0-r3} @ save r0-r3
mov r1, sp
add sp, sp, #16 @ restore sp
sub r2, lr, #4 @ save old task's pc to r2
mrs r3, spsr @ disable interrupt
orr r0, r3, #I_BIT|F_BIT
msr spsr_c, r0
ldr r0, =.+8 @ switch to interrupted task's stack
movs pc, r0
stmfd sp!, {r2} @ push old task's pc
stmfd sp!, {r4-r12,lr}@ push old task's lr,r12-r4
mov r4, r1 @ Special optimised code below
mov r5, r3
ldmfd r4!, {r0-r3}
stmfd sp!, {r0-r3} @ push old task's r3-r0
stmfd sp!, {r5} @ push old task's psr
mrs r4, spsr
stmfd sp!, {r4} @ push old task's spsr
ldr r4, =rt_interrupt_from_thread
ldr r5, [r4]
str sp, [r5] @ store sp in preempted tasks's TCB
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 spsr
msr SPSR_cxsf, r4
ldmfd sp!, {r4} @ pop new task's psr
msr CPSR_cxsf, r4
ldmfd sp!, {r0-r12,lr,pc} @ pop new task's r0-r12,lr & pc

View File

@@ -0,0 +1,517 @@
;/*****************************************************************************/
;/* SAM7.S: Startup file for Atmel AT91SAM7 device series */
;/*****************************************************************************/
;/* <<< Use Configuration Wizard in Context Menu >>> */
;/*****************************************************************************/
;/* This file is part of the uVision/ARM development tools. */
;/* Copyright (c) 2005-2006 Keil Software. All rights reserved. */
;/* This software may only be used under the terms of a valid, current, */
;/* end user licence from KEIL for a compatible version of KEIL software */
;/* development tools. Nothing else gives you the right to use this software. */
;/*****************************************************************************/
;/*
; * The SAM7.S code is executed after CPU Reset. This file may be
; * translated with the following SET symbols. In uVision these SET
; * symbols are entered under Options - ASM - Define.
; *
; * REMAP: when set the startup code remaps exception vectors from
; * on-chip RAM to address 0.
; *
; * RAM_INTVEC: when set the startup code copies exception vectors
; * from on-chip Flash to on-chip RAM.
; */
; Standard definitions of Mode bits and Interrupt (I & F) flags in PSRs
; 2009-12-28 MingBai Bug fix (USR mode stack removed).
; 2009-12-29 MingBai Merge svc and irq stack, add abort handler.
Mode_USR EQU 0x10
Mode_FIQ EQU 0x11
Mode_IRQ EQU 0x12
Mode_SVC EQU 0x13
Mode_ABT EQU 0x17
Mode_UND EQU 0x1B
Mode_SYS EQU 0x1F
I_Bit EQU 0x80 ; when I bit is set, IRQ is disabled
F_Bit EQU 0x40 ; when F bit is set, FIQ is disabled
; Internal Memory Base Addresses
FLASH_BASE EQU 0x00100000
RAM_BASE EQU 0x00200000
;// <h> Stack Configuration (Stack Sizes in Bytes)
;// <o0> Undefined Mode <0x0-0xFFFFFFFF:8>
;// <o1> Supervisor Mode <0x0-0xFFFFFFFF:8>
;// <o2> Abort Mode <0x0-0xFFFFFFFF:8>
;// <o3> Fast Interrupt Mode <0x0-0xFFFFFFFF:8>
;// <o4> Interrupt Mode <0x0-0xFFFFFFFF:8>
;// <o5> User/System Mode <0x0-0xFFFFFFFF:8>
;// </h>
UND_Stack_Size EQU 0x00000000
SVC_Stack_Size EQU 0x00000000
ABT_Stack_Size EQU 0x00000000
FIQ_Stack_Size EQU 0x00000000
IRQ_Stack_Size EQU 0x00000100
USR_Stack_Size EQU 0x00000000
ISR_Stack_Size EQU (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size)
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE USR_Stack_Size
__initial_sp SPACE ISR_Stack_Size
Stack_Top
;// <h> Heap Configuration
;// <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF>
;// </h>
Heap_Size EQU 0x00000000
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
; Reset Controller (RSTC) definitions
RSTC_BASE EQU 0xFFFFFD00 ; RSTC Base Address
RSTC_MR EQU 0x08 ; RSTC_MR Offset
;/*
;// <e> Reset Controller (RSTC)
;// <o1.0> URSTEN: User Reset Enable
;// <i> Enables NRST Pin to generate Reset
;// <o1.8..11> ERSTL: External Reset Length <0-15>
;// <i> External Reset Time in 2^(ERSTL+1) Slow Clock Cycles
;// </e>
;*/
RSTC_SETUP EQU 1
RSTC_MR_Val EQU 0xA5000401
; Embedded Flash Controller (EFC) definitions
EFC_BASE EQU 0xFFFFFF00 ; EFC Base Address
EFC0_FMR EQU 0x60 ; EFC0_FMR Offset
EFC1_FMR EQU 0x70 ; EFC1_FMR Offset
;// <e> Embedded Flash Controller 0 (EFC0)
;// <o1.16..23> FMCN: Flash Microsecond Cycle Number <0-255>
;// <i> Number of Master Clock Cycles in 1us
;// <o1.8..9> FWS: Flash Wait State
;// <0=> Read: 1 cycle / Write: 2 cycles
;// <1=> Read: 2 cycle / Write: 3 cycles
;// <2=> Read: 3 cycle / Write: 4 cycles
;// <3=> Read: 4 cycle / Write: 4 cycles
;// </e>
EFC0_SETUP EQU 1
EFC0_FMR_Val EQU 0x00320100
;// <e> Embedded Flash Controller 1 (EFC1)
;// <o1.16..23> FMCN: Flash Microsecond Cycle Number <0-255>
;// <i> Number of Master Clock Cycles in 1us
;// <o1.8..9> FWS: Flash Wait State
;// <0=> Read: 1 cycle / Write: 2 cycles
;// <1=> Read: 2 cycle / Write: 3 cycles
;// <2=> Read: 3 cycle / Write: 4 cycles
;// <3=> Read: 4 cycle / Write: 4 cycles
;// </e>
EFC1_SETUP EQU 0
EFC1_FMR_Val EQU 0x00320100
; Watchdog Timer (WDT) definitions
WDT_BASE EQU 0xFFFFFD40 ; WDT Base Address
WDT_MR EQU 0x04 ; WDT_MR Offset
;// <e> Watchdog Timer (WDT)
;// <o1.0..11> WDV: Watchdog Counter Value <0-4095>
;// <o1.16..27> WDD: Watchdog Delta Value <0-4095>
;// <o1.12> WDFIEN: Watchdog Fault Interrupt Enable
;// <o1.13> WDRSTEN: Watchdog Reset Enable
;// <o1.14> WDRPROC: Watchdog Reset Processor
;// <o1.28> WDDBGHLT: Watchdog Debug Halt
;// <o1.29> WDIDLEHLT: Watchdog Idle Halt
;// <o1.15> WDDIS: Watchdog Disable
;// </e>
WDT_SETUP EQU 1
WDT_MR_Val EQU 0x00008000
; Power Mangement Controller (PMC) definitions
PMC_BASE EQU 0xFFFFFC00 ; PMC Base Address
PMC_MOR EQU 0x20 ; PMC_MOR Offset
PMC_MCFR EQU 0x24 ; PMC_MCFR Offset
PMC_PLLR EQU 0x2C ; PMC_PLLR Offset
PMC_MCKR EQU 0x30 ; PMC_MCKR Offset
PMC_SR EQU 0x68 ; PMC_SR Offset
PMC_MOSCEN EQU (1<<0) ; Main Oscillator Enable
PMC_OSCBYPASS EQU (1<<1) ; Main Oscillator Bypass
PMC_OSCOUNT EQU (0xFF<<8) ; Main OScillator Start-up Time
PMC_DIV EQU (0xFF<<0) ; PLL Divider
PMC_PLLCOUNT EQU (0x3F<<8) ; PLL Lock Counter
PMC_OUT EQU (0x03<<14) ; PLL Clock Frequency Range
PMC_MUL EQU (0x7FF<<16) ; PLL Multiplier
PMC_USBDIV EQU (0x03<<28) ; USB Clock Divider
PMC_CSS EQU (3<<0) ; Clock Source Selection
PMC_PRES EQU (7<<2) ; Prescaler Selection
PMC_MOSCS EQU (1<<0) ; Main Oscillator Stable
PMC_LOCK EQU (1<<2) ; PLL Lock Status
PMC_MCKRDY EQU (1<<3) ; Master Clock Status
;// <e> Power Mangement Controller (PMC)
;// <h> Main Oscillator
;// <o1.0> MOSCEN: Main Oscillator Enable
;// <o1.1> OSCBYPASS: Oscillator Bypass
;// <o1.8..15> OSCCOUNT: Main Oscillator Startup Time <0-255>
;// </h>
;// <h> Phase Locked Loop (PLL)
;// <o2.0..7> DIV: PLL Divider <0-255>
;// <o2.16..26> MUL: PLL Multiplier <0-2047>
;// <i> PLL Output is multiplied by MUL+1
;// <o2.14..15> OUT: PLL Clock Frequency Range
;// <0=> 80..160MHz <1=> Reserved
;// <2=> 150..220MHz <3=> Reserved
;// <o2.8..13> PLLCOUNT: PLL Lock Counter <0-63>
;// <o2.28..29> USBDIV: USB Clock Divider
;// <0=> None <1=> 2 <2=> 4 <3=> Reserved
;// </h>
;// <o3.0..1> CSS: Clock Source Selection
;// <0=> Slow Clock
;// <1=> Main Clock
;// <2=> Reserved
;// <3=> PLL Clock
;// <o3.2..4> PRES: Prescaler
;// <0=> None
;// <1=> Clock / 2 <2=> Clock / 4
;// <3=> Clock / 8 <4=> Clock / 16
;// <5=> Clock / 32 <6=> Clock / 64
;// <7=> Reserved
;// </e>
PMC_SETUP EQU 1
PMC_MOR_Val EQU 0x00000601
PMC_PLLR_Val EQU 0x00191C05
PMC_MCKR_Val EQU 0x00000007
PRESERVE8
; Area Definition and Entry Point
; Startup Code must be linked first at Address at which it expects to run.
AREA RESET, CODE, READONLY
ARM
; Exception Vectors
; Mapped to Address 0.
; Absolute addressing mode must be used.
; Dummy Handlers are implemented as infinite loops which can be modified.
Vectors LDR PC,Reset_Addr
LDR PC,Undef_Addr
LDR PC,SWI_Addr
LDR PC,PAbt_Addr
LDR PC,DAbt_Addr
NOP ; Reserved Vector
LDR PC,IRQ_Addr
LDR PC,FIQ_Addr
Reset_Addr DCD Reset_Handler
Undef_Addr DCD Undef_Handler
SWI_Addr DCD SWI_Handler
PAbt_Addr DCD PAbt_Handler
DAbt_Addr DCD DAbt_Handler
DCD 0 ; Reserved Address
IRQ_Addr DCD IRQ_Handler
FIQ_Addr DCD FIQ_Handler
Undef_Handler B Undef_Handler
SWI_Handler B SWI_Handler
PAbt_Handler B Abort_Handler
DAbt_Handler B Abort_Handler
FIQ_Handler B FIQ_Handler
; Reset Handler
EXPORT Reset_Handler
Reset_Handler
; Setup RSTC
IF RSTC_SETUP != 0
LDR R0, =RSTC_BASE
LDR R1, =RSTC_MR_Val
STR R1, [R0, #RSTC_MR]
ENDIF
; Setup EFC0
IF EFC0_SETUP != 0
LDR R0, =EFC_BASE
LDR R1, =EFC0_FMR_Val
STR R1, [R0, #EFC0_FMR]
ENDIF
; Setup EFC1
IF EFC1_SETUP != 0
LDR R0, =EFC_BASE
LDR R1, =EFC1_FMR_Val
STR R1, [R0, #EFC1_FMR]
ENDIF
; Setup WDT
IF WDT_SETUP != 0
LDR R0, =WDT_BASE
LDR R1, =WDT_MR_Val
STR R1, [R0, #WDT_MR]
ENDIF
; Setup PMC
IF PMC_SETUP != 0
LDR R0, =PMC_BASE
; Setup Main Oscillator
LDR R1, =PMC_MOR_Val
STR R1, [R0, #PMC_MOR]
; Wait until Main Oscillator is stablilized
IF (PMC_MOR_Val:AND:PMC_MOSCEN) != 0
MOSCS_Loop LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_MOSCS
BEQ MOSCS_Loop
ENDIF
; Setup the PLL
IF (PMC_PLLR_Val:AND:PMC_MUL) != 0
LDR R1, =PMC_PLLR_Val
STR R1, [R0, #PMC_PLLR]
; Wait until PLL is stabilized
PLL_Loop LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_LOCK
BEQ PLL_Loop
ENDIF
; Select Clock
IF (PMC_MCKR_Val:AND:PMC_CSS) == 1 ; Main Clock Selected
LDR R1, =PMC_MCKR_Val
AND R1, #PMC_CSS
STR R1, [R0, #PMC_MCKR]
WAIT_Rdy1 LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_MCKRDY
BEQ WAIT_Rdy1
LDR R1, =PMC_MCKR_Val
STR R1, [R0, #PMC_MCKR]
WAIT_Rdy2 LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_MCKRDY
BEQ WAIT_Rdy2
ELIF (PMC_MCKR_Val:AND:PMC_CSS) == 3 ; PLL Clock Selected
LDR R1, =PMC_MCKR_Val
AND R1, #PMC_PRES
STR R1, [R0, #PMC_MCKR]
WAIT_Rdy1 LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_MCKRDY
BEQ WAIT_Rdy1
LDR R1, =PMC_MCKR_Val
STR R1, [R0, #PMC_MCKR]
WAIT_Rdy2 LDR R2, [R0, #PMC_SR]
ANDS R2, R2, #PMC_MCKRDY
BEQ WAIT_Rdy2
ENDIF ; Select Clock
ENDIF ; PMC_SETUP
; Copy Exception Vectors to Internal RAM
IF :DEF:RAM_INTVEC
ADR R8, Vectors ; Source
LDR R9, =RAM_BASE ; Destination
LDMIA R8!, {R0-R7} ; Load Vectors
STMIA R9!, {R0-R7} ; Store Vectors
LDMIA R8!, {R0-R7} ; Load Handler Addresses
STMIA R9!, {R0-R7} ; Store Handler Addresses
ENDIF
; Remap on-chip RAM to address 0
MC_BASE EQU 0xFFFFFF00 ; MC Base Address
MC_RCR EQU 0x00 ; MC_RCR Offset
IF :DEF:REMAP
LDR R0, =MC_BASE
MOV R1, #1
STR R1, [R0, #MC_RCR] ; Remap
ENDIF
; Setup Stack for each mode
LDR R0, =Stack_Top
; Enter Undefined Instruction Mode and set its Stack Pointer
MSR CPSR_c, #Mode_UND:OR:I_Bit:OR:F_Bit
MOV SP, R0
;SUB R0, R0, #UND_Stack_Size
; Enter Abort Mode and set its Stack Pointer
MSR CPSR_c, #Mode_ABT:OR:I_Bit:OR:F_Bit
MOV SP, R0
;SUB R0, R0, #ABT_Stack_Size
; Enter FIQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_FIQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
;SUB R0, R0, #FIQ_Stack_Size
; Enter IRQ Mode and set its Stack Pointer
MSR CPSR_c, #Mode_IRQ:OR:I_Bit:OR:F_Bit
MOV SP, R0
;SUB R0, R0, #IRQ_Stack_Size
; Enter Supervisor Mode and set its Stack Pointer
MSR CPSR_c, #Mode_SVC:OR:I_Bit:OR:F_Bit
MOV SP, R0
; SUB R0, R0, #SVC_Stack_Size
; Enter User Mode and set its Stack Pointer
; MSR CPSR_c, #Mode_USR
IF :DEF:__MICROLIB
EXPORT __initial_sp
ELSE
; No usr mode stack here.
;MOV SP, R0
;SUB SL, SP, #USR_Stack_Size
ENDIF
; Enter the C code
IMPORT __main
LDR R0, =__main
BX R0
IMPORT rt_interrupt_enter
IMPORT rt_interrupt_leave
IMPORT rt_thread_switch_interrupt_flag
IMPORT rt_interrupt_from_thread
IMPORT rt_interrupt_to_thread
IMPORT rt_hw_trap_irq
IMPORT rt_hw_trap_abort
IMPORT rt_interrupt_nest
Abort_Handler PROC
EXPORT Abort_Handler
stmfd sp!, {r0-r12,lr}
LDR r0, =rt_interrupt_nest
LDR r1, [r0]
CMP r1, #0
DeadLoop BHI DeadLoop ; Abort happened in irq mode, halt system.
bl rt_interrupt_enter
bl rt_hw_trap_abort
bl rt_interrupt_leave
b SWITCH
ENDP
IRQ_Handler PROC
EXPORT IRQ_Handler
STMFD sp!, {r0-r12,lr}
BL rt_interrupt_enter
BL rt_hw_trap_irq
BL rt_interrupt_leave
; if rt_thread_switch_interrupt_flag set, jump to
; rt_hw_context_switch_interrupt_do and don't return
SWITCH LDR r0, =rt_thread_switch_interrupt_flag
LDR r1, [r0]
CMP r1, #1
BEQ rt_hw_context_switch_interrupt_do
LDMFD sp!, {r0-r12,lr}
SUBS pc, lr, #4
ENDP
; /*
; * void rt_hw_context_switch_interrupt_do(rt_base_t flag)
; */
rt_hw_context_switch_interrupt_do PROC
EXPORT rt_hw_context_switch_interrupt_do
MOV r1, #0 ; clear flag
STR r1, [r0]
LDMFD sp!, {r0-r12,lr}; reload saved registers
STMFD sp!, {r0-r3} ; save r0-r3
MOV r1, sp
ADD sp, sp, #16 ; restore sp
SUB r2, lr, #4 ; save old task's pc to r2
MRS r3, spsr ; get cpsr of interrupt thread
; switch to SVC mode and no interrupt
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
MOV r4, r1 ; Special optimised code below
MOV r5, r3
LDMFD r4!, {r0-r3}
STMFD sp!, {r0-r3} ; push old task's r3-r0
STMFD sp!, {r5} ; push old task's cpsr
MRS r4, spsr
STMFD sp!, {r4} ; push old task's spsr
LDR r4, =rt_interrupt_from_thread
LDR r5, [r4]
STR sp, [r5] ; store sp in preempted tasks's TCB
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 spsr
MSR spsr_cxsf, r4
LDMFD sp!, {r4} ; pop new task's psr
MSR cpsr_cxsf, r4
LDMFD sp!, {r0-r12,lr,pc} ; pop new task's r0-r12,lr & pc
ENDP
IF :DEF:__MICROLIB
EXPORT __heap_base
EXPORT __heap_limit
ELSE
; User Initial Stack & Heap
AREA |.text|, CODE, READONLY
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem
LDR R1, = (Stack_Mem + IRQ_Stack_Size)
LDR R2, = (Heap_Mem + Heap_Size)
LDR R3, = Stack_Mem
BX LR
ENDIF
END

View File

@@ -0,0 +1,49 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2006-08-25 Bernard first version
*/
#include <rtthread.h>
#include <rthw.h>
#include "AT91SAM7X256.h"
/**
* @addtogroup AT91SAM7
*/
/*@{*/
void rt_hw_trap_irq(void)
{
int irqno;
extern struct rt_irq_desc irq_desc[];
/* get interrupt number */
irqno = AT91C_BASE_AIC->AIC_ISR;
/* invoke isr with parameters */
irq_desc[irqno].handler(irqno, irq_desc[irqno].param);
/* end of interrupt */
AT91C_BASE_AIC->AIC_EOICR = 0;
}
void rt_hw_trap_fiq(void)
{
rt_kprintf("fast interrupt request\n");
}
extern struct rt_thread* rt_current_thread;
void rt_hw_trap_abort(void)
{
rt_kprintf("Abort occured!!! Thread [%s] suspended.\n",rt_current_thread->parent.name);
rt_thread_suspend(rt_current_thread);
rt_schedule();
}
/*@}*/

View File

@@ -0,0 +1,18 @@
# RT-Thread building script for bridge
import os
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
list = os.listdir(cwd)
# add common code files
group = SConscript(os.path.join('common', 'SConscript'))
# cpu porting code files
if rtconfig.CPU in list:
group = group + SConscript(os.path.join(rtconfig.CPU, 'SConscript'))
Return('group')

View File

@@ -0,0 +1,23 @@
# RT-Thread building script for component
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')
CPPPATH = [cwd]
if rtconfig.PLATFORM in ['armcc', 'armclang']:
src += Glob('*_rvds.S')
if rtconfig.PLATFORM in ['gcc']:
src += Glob('*_init.S')
src += Glob('*_gcc.S')
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@@ -0,0 +1,354 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef __AM33XX_H__
#define __AM33XX_H__
#define REG32(x) (*((volatile unsigned int *)(x)))
#define REG16(x) (*((volatile unsigned short *)(x)))
/** Cache Line size in ARM Cortex-A8. */
#define AM33XX_CACHELINE_SIZE (64)
/** @brief Base address of AINTC memory mapped registers */
#define AM33XX_AINTC_REGS (0x48200000)
/** @brief Base addresses of control module registers */
#define AM33XX_CTLM_REGS (0x44e10000)
/** @brief Base addresses of USB memory mapped registers */
#define AM33XX_USB_0_BASE (0x47401400)
#define AM33XX_USB_1_BASE (0x47401C00)
/** @brief Base addresses of SPI memory mapped registers */
#define AM33XX_SPI_0_REGS (0x48030000)
#define AM33XX_SPI_1_REGS (0x481A0000)
/** @brief Base addresses of GPIO memory mapped registers */
#define AM33XX_GPIO_0_REGS (0x44E07000)
#define AM33XX_GPIO_1_REGS (0x4804C000)
#define AM33XX_GPIO_2_REGS (0x481AC000)
#define AM33XX_GPIO_3_REGS (0x481AE000)
/** @brief Base addresses of DMTIMER memory mapped registers */
#define AM33XX_DMTIMER_0_REGS (0x44E05000)
#define AM33XX_DMTIMER_1_REGS (0x44E31000)
#define AM33XX_DMTIMER_2_REGS (0x48040000)
#define AM33XX_DMTIMER_3_REGS (0x48042000)
#define AM33XX_DMTIMER_4_REGS (0x48044000)
#define AM33XX_DMTIMER_5_REGS (0x48046000)
#define AM33XX_DMTIMER_6_REGS (0x48048000)
#define AM33XX_DMTIMER_7_REGS (0x4804A000)
/** @brief Base address of MMC memory mapped registers */
#define AM33XX_MMCHS_0_REGS (0x48060000)
#define AM33XX_MMCHS_1_REGS (0x481D8000)
#define AM33XX_MMCHS_2_REGS (0x47810000)
/** @brief Base address of GPMC memory mapped registers */
#define AM33XX_GPMC_0_REGS (0x50000000)
/** @brief Base address of GPMC memory mapped registers */
#define AM33XX_ELM_0_REGS (0x48080000)
/** @brief Base address of I2C memory mapped registers */
#define AM33XX_I2C_0_REGS (0x44E0B000)
#define AM33XX_I2C_1_REGS (0x4802A000)
#define AM33XX_I2C_2_REGS (0x4819C000)
/** @brief Base address of WDT memory mapped registers */
#define AM33XX_WDT_0_REGS (0x44E33000)
#define AM33XX_WDT_1_REGS (0x44E35000)
/** @brief Base address of WDT memory mapped registers */
#define AM33XX_CPSW_SS_REGS (0x4A100000)
#define AM33XX_CPSW_MDIO_REGS (0x4A101000)
#define AM33XX_CPSW_WR_REGS (0x4A101200)
#define AM33XX_CPSW_CPDMA_REGS (0x4A100800)
#define AM33XX_CPSW_ALE_REGS (0x4A100D00)
#define AM33XX_CPSW_STAT_REGS (0x4A100900)
#define AM33XX_CPSW_PORT_0_REGS (0x4A100100)
#define AM33XX_CPSW_PORT_1_REGS (0x4A100200)
#define AM33XX_CPSW_SLIVER_1_REGS (0x4A100D80)
#define AM33XX_CPSW_PORT_2_REGS (0x4A100300)
#define AM33XX_CPSW_SLIVER_2_REGS (0x4A100DC0)
#define AM33XX_CPSW_CPPI_RAM_REGS (0x4A102000)
/** @brief Base address of McASP memory mapped registers */
#define AM33XX_MCASP_1_CTRL_REGS (0x4803C000)
#define AM33XX_MCASP_1_FIFO_REGS (AM33XX_MCASP_1_CTRL_REGS + 0x1000)
#define AM33XX_MCASP_1_DATA_REGS (0x46400000)
/** @brief Base address of EMIF memory mapped registers */
#define AM33XX_EMIF_0_REGS (0x4C000000)
/** @brief Base addresses of RTC memory mapped registers */
#define AM33XX_RTC_0_REGS (0x44E3E000)
#define CM_PER(base) ((base) + 0)
#define CM_PER_L4LS_CLKSTCTRL(base) (CM_PER(base) + 0)
#define CM_PER_UART1_CLKCTRL(base) (CM_PER(base) + 0x6C)
#define CM_PER_UART2_CLKCTRL(base) (CM_PER(base) + 0x70)
#define CM_PER_UART3_CLKCTRL(base) (CM_PER(base) + 0x74)
#define CM_PER_UART4_CLKCTRL(base) (CM_PER(base) + 0x78)
#define CM_PER_UART5_CLKCTRL(base) (CM_PER(base) + 0x38)
#define CM_WKUP(base) ((base) + 0x400)
#define CM_WKUP_CLKSTCTRL(base) (CM_WKUP(base) + 0)
#define CM_WKUP_UART0_CLKCTRL(base) (CM_WKUP(base) + 0xB4)
#define CM_DPLL(base) ((base) + 0x500)
#define CM_MPU(base) ((base) + 0x600)
#define CM_DEVICE(base) ((base) + 0x700)
#define CM_RTC(base) ((base) + 0x800)
#define CM_GFX(base) ((base) + 0x900)
#define CM_CEFUSE(base) ((base) + 0xA00)
#define OCP_AM33XXKET_RAM(base) ((base) + 0xB00)
#define PRM_PER(base) ((base) + 0xC00)
#define PRM_PER_PWRSTST(base) (PRM_PER(base) + 0x008)
#define PRM_PER_PWRSTCTRL(base) (PRM_PER(base) + 0x00C)
#define PRM_WKUP(base) ((base) + 0xD00)
#define PRM_MPU(base) ((base) + 0xE00)
#define PRM_DEVICE(base) ((base) + 0xF00)
#define PRM_RTC(base) ((base) + 0x1000)
#define PRM_GFX(base) ((base) + 0x1100)
#define PRM_CEFUSE(base) ((base) + 0x1200)
/** @brief Base addresses of PRCM memory mapped registers */
#define AM33XX_PRCM_REGS (0x44E00000)
#define AM33XX_CM_PER_REGS CM_PER(AM33XX_PRCM_REGS)
#define AM33XX_CM_WKUP_REGS CM_WKUP(AM33XX_PRCM_REGS)
#define AM33XX_CM_DPLL_REGS CM_DPLL(AM33XX_PRCM_REGS)
#define AM33XX_CM_MPU_REGS CM_MPU(AM33XX_PRCM_REGS)
#define AM33XX_CM_DEVICE_REGS CM_DEVICE(AM33XX_PRCM_REGS)
#define AM33XX_CM_RTC_REGS CM_RTC(AM33XX_PRCM_REGS)
#define AM33XX_CM_GFX_REGS CM_GFX(AM33XX_PRCM_REGS)
#define AM33XX_CM_CEFUSE_REGS CM_CEFUSE(AM33XX_PRCM_REGS)
#define AM33XX_OCP_AM33XXKET_RAM_REGS OCP_AM33XXKET_RAM(AM33XX_PRCM_REGS)
#define AM33XX_PRM_PER_REGS PRM_PER(AM33XX_PRCM_REGS)
#define AM33XX_PRM_WKUP_REGS PRM_WKUP(AM33XX_PRCM_REGS)
#define AM33XX_PRM_MPU_REGS PRM_MPU(AM33XX_PRCM_REGS)
#define AM33XX_PRM_DEVICE_REGS PRM_DEVICE(AM33XX_PRCM_REGS)
#define AM33XX_PRM_RTC_REGS PRM_RTC(AM33XX_PRCM_REGS)
#define AM33XX_PRM_GFX_REGS PRM_GFX(AM33XX_PRCM_REGS)
#define AM33XX_PRM_CEFUSE_REGS PRM_CEFUSE(AM33XX_PRCM_REGS)
/** @brief Base address of control module memory mapped registers */
#define AM33XX_CONTROL_REGS (0x44E10000)
/** @brief Base address of Channel controller memory mapped registers */
#define AM33XX_EDMA30CC_0_REGS (0x49000000)
/** @brief Base address of DCAN module memory mapped registers */
#define AM33XX_DCAN_0_REGS (0x481CC000)
#define AM33XX_DCAN_1_REGS (0x481D0000)
/******************************************************************************\
* Parameterizable Configuration:- These are fed directly from the RTL
* parameters for the given AM33XX
\******************************************************************************/
#define TPCC_MUX(n) 0xF90 + ((n) * 4)
#define AM33XX_LCDC_0_REGS 0x4830E000
#define AM33XX_ADC_TSC_0_REGS 0x44E0D000
/** @brief Base addresses of PWMSS memory mapped registers. */
#define AM33XX_PWMSS0_REGS (0x48300000)
#define AM33XX_PWMSS1_REGS (0x48302000)
#define AM33XX_PWMSS2_REGS (0x48304000)
#define AM33XX_ECAP_REGS (0x00000100)
#define AM33XX_EQEP_REGS (0x00000180)
#define AM33XX_EPWM_REGS (0x00000200)
#define AM33XX_ECAP_0_REGS (AM33XX_PWMSS0_REGS + AM33XX_ECAP_REGS)
#define AM33XX_ECAP_1_REGS (AM33XX_PWMSS1_REGS + AM33XX_ECAP_REGS)
#define AM33XX_ECAP_2_REGS (AM33XX_PWMSS2_REGS + AM33XX_ECAP_REGS)
#define AM33XX_EQEP_0_REGS (AM33XX_PWMSS0_REGS + AM33XX_EQEP_REGS)
#define AM33XX_EQEP_1_REGS (AM33XX_PWMSS1_REGS + AM33XX_EQEP_REGS)
#define AM33XX_EQEP_2_REGS (AM33XX_PWMSS2_REGS + AM33XX_EQEP_REGS)
#define AM33XX_EPWM_0_REGS (AM33XX_PWMSS0_REGS + AM33XX_EPWM_REGS)
#define AM33XX_EPWM_1_REGS (AM33XX_PWMSS1_REGS + AM33XX_EPWM_REGS)
#define AM33XX_EPWM_2_REGS (AM33XX_PWMSS2_REGS + AM33XX_EPWM_REGS)
#define AM33XX_EPWM_MODULE_FREQ 100
/* PRCM registers */
#define CM_PER_L4LS_CLKSTCTRL_REG(base) REG32((base) + 0x0)
#define CM_PER_UART1_CLKCTRL_REG(base) REG32(CM_PER_UART1_CLKCTRL(base))
#define CM_PER_UART2_CLKCTRL_REG(base) REG32(CM_PER_UART2_CLKCTRL(base))
#define CM_PER_UART3_CLKCTRL_REG(base) REG32(CM_PER_UART3_CLKCTRL(base))
#define CM_PER_UART4_CLKCTRL_REG(base) REG32(CM_PER_UART4_CLKCTRL(base))
#define CM_PER_UART5_CLKCTRL_REG(base) REG32(CM_PER_UART5_CLKCTRL(base))
#define CM_PER_TIMER7_CLKCTRL(base) REG32((base) + 0x7C)
#define CM_PER_TIMER2_CLKCTRL(base) REG32((base) + 0x80)
#define PRM_PER_PWRSTST_REG(base) REG32(PRM_PER_PWRSTST(base))
#define PRM_PER_PWRSTCTRL_REG(base) REG32(PRM_PER_PWRSTCTRL(base))
#define CM_WKUP_CLKSTCTRL_REG(base) REG32(CM_WKUP_CLKSTCTRL(base))
#define CM_WKUP_UART0_CLKCTRL_REG(base) REG32(CM_WKUP_UART0_CLKCTRL(base))
#define CM_DPLL_CLKSEL_TIMER7_CLK(base) REG32(CM_DPLL(base) + 0x4)
#define CM_DPLL_CLKSEL_TIMER2_CLK(base) REG32(CM_DPLL(base) + 0x8)
/* timer registers */
#define DMTIMER_TIDR(base) REG32(base + 0x0)
#define DMTIMER_TIOCP_CFG(base) REG32(base + 0x10)
#define DMTIMER_IRQ_EOI(base) REG32(base + 0x20)
#define DMTIMER_IRQSTATUS_RAW(base) REG32(base + 0x24)
#define DMTIMER_IRQSTATUS(base) REG32(base + 0x28)
#define DMTIMER_IRQENABLE_SET(base) REG32(base + 0x2C)
#define DMTIMER_IRQENABLE_CLR(base) REG32(base + 0x30)
#define DMTIMER_IRQWAKEEN(base) REG32(base + 0x34)
#define DMTIMER_TCLR(base) REG32(base + 0x38)
#define DMTIMER_TCRR(base) REG32(base + 0x3C)
#define DMTIMER_TLDR(base) REG32(base + 0x40)
#define DMTIMER_TTGR(base) REG32(base + 0x44)
#define DMTIMER_TWPS(base) REG32(base + 0x48)
#define DMTIMER_TMAR(base) REG32(base + 0x4C)
#define DMTIMER_TCAR(base, n) REG32(base + 0x50 + (((n) - 1) * 8))
#define DMTIMER_TSICR(base) REG32(base + 0x54)
#define EMU_INT 0
#define COMMTX_INT 1
#define COMMRX_INT 2
#define BENCH_INT 3
#define ELM_IRQ_INT 4
#define NMI_INT 7
#define L3DEBUG_INT 9
#define L3APP_INT 10
#define PRCM_INT 11
#define EDMACOMP_INT 12
#define EDMAMPERR_INT 13
#define EDMAERR_INT 14
#define ADC_TSC_GEN_INT 16
#define USBSS_INT 17
#define USB_INT0 18
#define USB_INT1 19
#define PRU_ICSS_EVTOUT0_INT 20
#define PRU_ICSS_EVTOUT1_INT 21
#define PRU_ICSS_EVTOUT2_INT 22
#define PRU_ICSS_EVTOUT3_INT 23
#define PRU_ICSS_EVTOUT4_INT 24
#define PRU_ICSS_EVTOUT5_INT 25
#define PRU_ICSS_EVTOUT6_INT 26
#define PRU_ICSS_EVTOUT7_INT 27
#define MMCSD1_INT 28
#define MMCSD2_INT 29
#define I2C2_INT 30
#define ECAP0_INT 31
#define GPIO_INT2A 32
#define GPIO_INT2B 33
#define USBWAKEUP_INT 34
#define LCDC_INT 36
#define GFX_INT 37
#define EPWM2_INT 39
#define CPSW_RXTHR0_INT 40
#define CPSW_RX_INT0 41
#define CPSW_TX_INT0 42
#define CPSW_MISC0_INT 43
#define UART3_INT 44
#define UART4_INT 45
#define UART5_INT 46
#define ECAP1_INT 47
#define DCAN0_INT0 52
#define DCAN0_INT1 53
#define DCAN0_PARITY 54
#define DCAN1_INT0 55
#define DCAN1_INT1 56
#define DCAN1_PARITY 57
#define EPWM0_TZINT 58
#define EPWM1_TZINT 59
#define EPWM2_TZINT 60
#define ECAP2_INT 61
#define GPIO_INT3A 62
#define GPIO_INT3B 63
#define MMCSD0_INT 64
#define MCSPI0_INT 65
#define TINT0 66
#define TINT1_1MS 67
#define TINT2 68
#define TINT3 69
#define I2C0_INT 70
#define I2C1_INT 71
#define UART0_INT 72
#define UART1_INT 73
#define UART2_INT 74
#define RTC_INT 75
#define RTC_ALARM_INT 76
#define MB_INT0 77
#define M3_TXEV 78
#define EQEP0_INT 79
#define MACTX_INT0 80
#define MCARX_INT0 81
#define MCATX_INT1 82
#define MCARX_INT1 83
#define EPWM0_INT 86
#define EPWM1_INT 87
#define EQEP1_INT 88
#define EQEP2_INT 89
#define DMA_INTR_PIN2 90
#define WDT1_INT 91
#define TINT4 92
#define TINT5 93
#define TINT6 94
#define TINT7 95
#define GPIO_INT0A 96
#define GPIO_INT0B 97
#define GPIO_INT1A 98
#define GPIO_INT1B 99
#define GPMC_INT 100
#define DDRERR0 101
#define TCERR_INT0 112
#define TCERR_INT1 113
#define TCERR_INT2 114
#define ADC_TSC_PEN_INT 115
#define SMRFLX_MPU 120
#define SMRFLX_CORE 121
#define DMA_INTR_PIN0 123
#define DMA_INTR_PIN1 124
#define MCSPI1_INT 125
struct rt_hw_register
{
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;
unsigned long ORIG_r0;
};
#define USERMODE 0x10
#define FIQMODE 0x11
#define IRQMODE 0x12
#define SVCMODE 0x13
#define ABORTMODE 0x17
#define UNDEFMODE 0x1b
#define MODEMASK 0x1f
#define NOINT 0xc0
#endif

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-05 Bernard the first version
*/
/*
* rt_base_t rt_hw_interrupt_disable();
*/
.globl rt_hw_interrupt_disable
rt_hw_interrupt_disable:
mrs r0, cpsr
cpsid if
bx lr
/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
.globl rt_hw_interrupt_enable
rt_hw_interrupt_enable:
msr cpsr_c, r0
bx lr
/*
* 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
ldmfd sp!, {r4} @ pop new task cpsr to spsr
msr spsr_cxsf, r4
_do_switch:
ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr
/*
* 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
/*
* 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
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
str r3, [r2]
ldr r2, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
str r0, [r2]
_reswitch:
ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
str r1, [r2]
bx lr

View File

@@ -0,0 +1,86 @@
;/*
; * Copyright (c) 2006-2021, RT-Thread Development Team
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Change Logs:
; * Date Author Notes
; * 2011-08-14 weety copy from mini2440
; * 2015-04-15 ArdaFu convert from context_gcc.s
; */
#define NOINT 0xc0
SECTION .text:CODE(6)
/*
* rt_base_t rt_hw_interrupt_disable();
*/
PUBLIC rt_hw_interrupt_disable
rt_hw_interrupt_disable:
MRS R0, CPSR
ORR R1, R0, #NOINT
MSR CPSR_C, R1
MOV PC, LR
/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
PUBLIC rt_hw_interrupt_enable
rt_hw_interrupt_enable:
MSR CPSR_CXSF, R0
MOV PC, LR
/*
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
* r0 --> from
* r1 --> to
*/
PUBLIC 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
LDMFD SP!, {R4} ; pop new task spsr
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc
/*
* void rt_hw_context_switch_to(rt_uint32 to);
* r0 --> to
*/
PUBLIC 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
/*
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
*/
IMPORT rt_thread_switch_interrupt_flag
IMPORT rt_interrupt_from_thread
IMPORT rt_interrupt_to_thread
PUBLIC 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
MOV R3, #1 ; set flag to 1
STR R3, [R2]
LDR R2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
STR R0, [R2]
_reswitch:
LDR R2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
STR R1, [R2]
MOV PC, LR
END

View File

@@ -0,0 +1,130 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-05 Bernard the first version
*/
.globl rt_cpu_vector_set_base
rt_cpu_vector_set_base:
mcr p15, #0, r0, c12, c0, #0
dsb
bx lr
.globl rt_cpu_vector_get_base
rt_cpu_vector_get_base:
mrc p15, #0, r0, c12, c0, #0
bx lr
.globl rt_cpu_get_sctlr
rt_cpu_get_sctlr:
mrc p15, #0, r0, c1, c0, #0
bx lr
.globl rt_cpu_dcache_enable
rt_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_cpu_icache_enable
rt_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_cpu_dcache_disable
rt_cpu_dcache_disable:
push {r4-r11, lr}
mrc p15, #0, r0, c1, c0, #0
bic r0, r0, #0x00000004
mcr p15, #0, r0, c1, c0, #0
bl rt_cpu_dcache_clean_flush
pop {r4-r11, lr}
bx lr
.globl rt_cpu_icache_disable
rt_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

View File

@@ -0,0 +1,139 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-04-06 zchong change to iar compiler from convert from cp15_gcc.S
*/
SECTION .text:CODE:NOROOT(2)
ARM
EXPORT rt_cpu_vector_set_base
rt_cpu_vector_set_base:
MCR p15, #0, r0, c12, c0, #0
DSB
BX lr
EXPORT rt_cpu_vector_get_base
rt_cpu_vector_get_base:
MRC p15, #0, r0, c12, c0, #0
BX lr
EXPORT rt_cpu_get_sctlr
rt_cpu_get_sctlr:
MRC p15, #0, r0, c1, c0, #0
BX lr
EXPORT rt_cpu_dcache_enable
rt_cpu_dcache_enable:
MRC p15, #0, r0, c1, c0, #0
ORR r0, r0, #0x00000004
MCR p15, #0, r0, c1, c0, #0
BX lr
EXPORT rt_cpu_icache_enable
rt_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 DEFINE 0x3ff
;_FLD_MAX_IDX DEFINE 0x7ff
EXPORT 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
LDR r4, =0x3FF
ANDS r4, r4, r1, lsr #3
CLZ r5, r4
;LDR r7, _FLD_MAX_IDX
LDR r7, =0x7FF
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
EXPORT rt_cpu_dcache_disable
rt_cpu_dcache_disable:
PUSH {r4-r11, lr}
MRC p15, #0, r0, c1, c0, #0
BIC r0, r0, #0x00000004
MCR p15, #0, r0, c1, c0, #0
BL rt_cpu_dcache_clean_flush
POP {r4-r11, lr}
BX lr
EXPORT rt_cpu_icache_disable
rt_cpu_icache_disable:
MRC p15, #0, r0, c1, c0, #0
BIC r0, r0, #0x00001000
MCR p15, #0, r0, c1, c0, #0
BX lr
EXPORT 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
EXPORT 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
EXPORT rt_cpu_tlb_set
rt_cpu_tlb_set:
MCR p15, #0, r0, c2, c0, #0
DMB
BX lr
END

View File

@@ -0,0 +1,197 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-09-15 Bernard first version
* 2022-09-20 YangZhongQing
* add IAR assembler
*/
#include <rthw.h>
#include <rtthread.h>
#include "am33xx.h"
/**
* @addtogroup AM33xx
*/
/*@{*/
#define ICACHE_MASK (rt_uint32_t)(1 << 12)
#define DCACHE_MASK (rt_uint32_t)(1 << 2)
#if defined(__CC_ARM)
rt_inline rt_uint32_t cp15_rd(void)
{
rt_uint32_t i;
__asm
{
mrc p15, 0, i, c1, c0, 0
}
return i;
}
rt_inline void cache_enable(rt_uint32_t bit)
{
rt_uint32_t value;
__asm
{
mrc p15, 0, value, c1, c0, 0
orr value, value, bit
mcr p15, 0, value, c1, c0, 0
}
}
rt_inline void cache_disable(rt_uint32_t bit)
{
rt_uint32_t value;
__asm
{
mrc p15, 0, value, c1, c0, 0
bic value, value, bit
mcr p15, 0, value, c1, c0, 0
}
}
#elif defined(__GNUC__)
rt_inline rt_uint32_t cp15_rd(void)
{
rt_uint32_t i;
asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
return i;
}
rt_inline void cache_enable(rt_uint32_t bit)
{
__asm__ __volatile__( \
"mrc p15,0,r0,c1,c0,0\n\t" \
"orr r0,r0,%0\n\t" \
"mcr p15,0,r0,c1,c0,0" \
: \
:"r" (bit) \
:"memory");
}
rt_inline void cache_disable(rt_uint32_t bit)
{
__asm__ __volatile__( \
"mrc p15,0,r0,c1,c0,0\n\t" \
"bic r0,r0,%0\n\t" \
"mcr p15,0,r0,c1,c0,0" \
: \
:"r" (bit) \
:"memory");
}
#elif defined(__ICCARM__)
rt_inline rt_uint32_t cp15_rd(void)
{
rt_uint32_t i;
__asm volatile("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
return i;
}
rt_inline void cache_enable(rt_uint32_t bit)
{
rt_uint32_t tmp;
__asm volatile( \
"mrc p15,0,%0,c1,c0,0\n\t" \
"orr %0,%0,%1\n\t" \
"mcr p15,0,%0,c1,c0,0" \
:"+r"(tmp) \
:"r"(bit) \
:"memory");
}
rt_inline void cache_disable(rt_uint32_t bit)
{
rt_uint32_t tmp;
__asm volatile( \
"mrc p15,0,%0,c1,c0,0\n\t" \
"bic %0,%0,%1\n\t" \
"mcr p15,0,%0,c1,c0,0" \
:"+r"(tmp) \
:"r"(bit) \
:"memory");
}
#endif
/**
* enable I-Cache
*
*/
void rt_hw_cpu_icache_enable()
{
cache_enable(ICACHE_MASK);
}
/**
* disable I-Cache
*
*/
void rt_hw_cpu_icache_disable()
{
cache_disable(ICACHE_MASK);
}
/**
* return the status of I-Cache
*
*/
rt_base_t rt_hw_cpu_icache_status()
{
return (cp15_rd() & ICACHE_MASK);
}
/**
* enable D-Cache
*
*/
void rt_hw_cpu_dcache_enable()
{
cache_enable(DCACHE_MASK);
}
/**
* disable D-Cache
*
*/
void rt_hw_cpu_dcache_disable()
{
cache_disable(DCACHE_MASK);
}
/**
* return the status of D-Cache
*
*/
rt_base_t rt_hw_cpu_dcache_status()
{
return (cp15_rd() & DCACHE_MASK);
}
/**
* shutdown CPU
*
*/
void rt_hw_cpu_shutdown(void)
{
rt_base_t level;
rt_kprintf("shutdown...\n");
level = rt_hw_interrupt_disable();
while (level)
{
RT_ASSERT(0);
}
}
/*@}*/

View File

@@ -0,0 +1,23 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef CPUPORT_H__
#define CPUPORT_H__
#ifdef RT_USING_SMP
typedef union {
unsigned long slock;
struct __arch_tickets {
unsigned short owner;
unsigned short next;
} tickets;
} rt_hw_spinlock_t;
#endif
#endif /*CPUPORT_H__*/

View File

@@ -0,0 +1,223 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-06 Bernard first version
* 2015-11-06 zchong support iar compiler
*/
#include <rthw.h>
#include <rtthread.h>
#include "am33xx.h"
#include "interrupt.h"
#define AINTC_BASE AM33XX_AINTC_REGS
#define MAX_HANDLERS 128
extern volatile rt_uint8_t rt_interrupt_nest;
/* exception and interrupt handler table */
struct rt_irq_desc isr_table[MAX_HANDLERS];
rt_uint32_t rt_interrupt_from_thread, rt_interrupt_to_thread;
rt_uint32_t rt_thread_switch_interrupt_flag;
/**
* @addtogroup AM33xx
*/
/*@{*/
void rt_dump_aintc(void)
{
int k;
rt_kprintf("active irq %d", INTC_SIR_IRQ(AINTC_BASE));
rt_kprintf("\n--- hw mask ---\n");
for (k = 0; k < 4; k++)
{
rt_kprintf("0x%08x, ", INTC_MIR(AINTC_BASE, k));
}
rt_kprintf("\n--- hw itr ---\n");
for (k = 0; k < 4; k++)
{
rt_kprintf("0x%08x, ", INTC_ITR(AINTC_BASE, k));
}
rt_kprintf("\n");
}
const unsigned int AM335X_VECTOR_BASE = 0x4030FC00;
extern void rt_cpu_vector_set_base(unsigned int addr);
#ifdef __ICCARM__
extern int __vector;
#else
extern int system_vectors;
#endif
static void rt_hw_vector_init(void)
{
unsigned int *dest = (unsigned int *)AM335X_VECTOR_BASE;
#ifdef __ICCARM__
unsigned int *src = (unsigned int *)&__vector;
#else
unsigned int *src = (unsigned int *)&system_vectors;
#endif
rt_memcpy(dest, src, 16 * 4);
rt_cpu_vector_set_base(AM335X_VECTOR_BASE);
}
/**
* This function will initialize hardware interrupt
*/
void rt_hw_interrupt_init(void)
{
/* Reset the ARM interrupt controller */
INTC_SYSCONFIG(AINTC_BASE) = INTC_SYSCONFIG_SOFTRESET;
/* Wait for the reset to complete */
while((INTC_SYSSTATUS(AINTC_BASE)
& INTC_SYSSTATUS_RESETDONE) != INTC_SYSSTATUS_RESETDONE);
/* Enable any interrupt generation by setting priority threshold */
INTC_THRESHOLD(AINTC_BASE) = INTC_THRESHOLD_PRIORITYTHRESHOLD;
/* initialize vector table */
rt_hw_vector_init();
/* init exceptions table */
rt_memset(isr_table, 0x00, sizeof(isr_table));
/* 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)
{
INTC_MIR_SET(AINTC_BASE, vector >> 0x05) = 0x1 << (vector & 0x1f);
}
/**
* This function will un-mask a interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_umask(int vector)
{
INTC_MIR_CLEAR(AINTC_BASE, vector >> 0x05) = 0x1 << (vector & 0x1f);
}
/**
* This function will control the interrupt attribute.
* @param vector the interrupt number
*/
void rt_hw_interrupt_control(int vector, int priority, int route)
{
int fiq;
if (route == 0)
fiq = 0;
else
fiq = 1;
INTC_ILR(AINTC_BASE, vector) = ((priority << 0x02) & 0x1FC) | fiq ;
}
int rt_hw_interrupt_get_active(int fiq_irq)
{
int ir;
if (fiq_irq == INT_FIQ)
{
ir = INTC_SIR_FIQ(AINTC_BASE) & 0x7f;
}
else
{
ir = INTC_SIR_IRQ(AINTC_BASE) & 0x7f;
}
return ir;
}
void rt_hw_interrupt_ack(int fiq_irq)
{
if (fiq_irq == INT_FIQ)
{
/* new FIQ generation */
INTC_CONTROL(AINTC_BASE) |= 0x02;
}
else
{
/* new IRQ generation */
INTC_CONTROL(AINTC_BASE) |= 0x01;
}
}
/**
* 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, const 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;
}
/**
* This function will trigger an interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_trigger(int vector)
{
INTC_ISR_SET(AINTC_BASE, vector>>5) = 1 << (vector & 0x1f);
}
void rt_hw_interrupt_clear(int vector)
{
INTC_ISR_CLEAR(AINTC_BASE, vector>>5) = 1 << (vector & 0x1f);
}
void rt_dump_isr_table(void)
{
int idx;
for(idx = 0; idx < MAX_HANDLERS; idx++)
{
#ifdef RT_USING_INTERRUPT_INFO
rt_kprintf("nr:%4d, name: %*.s, handler: 0x%p, param: 0x%08x\r\n",
idx, RT_NAME_MAX, isr_table[idx].name,
isr_table[idx].handler, isr_table[idx].param);
#else
rt_kprintf("nr:%4d, handler: 0x%p, param: 0x%08x\r\n",
idx, isr_table[idx].handler, isr_table[idx].param);
#endif
}
}
/*@}*/

View File

@@ -0,0 +1,255 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* 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
/*************************************************************************\
* Registers Definition
\*************************************************************************/
#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))
/**************************************************************************\
* Field Definition Macros
\**************************************************************************/
/* REVISION */
#define INTC_REVISION_REV (0x000000FFu)
#define INTC_REVISION_REV_SHIFT (0x00000000u)
/* SYSCONFIG */
#define INTC_SYSCONFIG_SOFTRESET (0x00000002u)
#define INTC_SYSCONFIG_SOFTRESET_SHIFT (0x00000001u)
#define INTC_SYSCONFIG_AUTOIDLE (0x00000001u)
#define INTC_SYSCONFIG_AUTOIDLE_SHIFT (0x00000000u)
/* SYSSTATUS */
#define INTC_SYSSTATUS_RESETDONE (0x00000001u)
#define INTC_SYSSTATUS_RESETDONE_SHIFT (0x00000000u)
/* SIR_IRQ */
#define INTC_SIR_IRQ_SPURIOUSIRQ (0xFFFFFF80u)
#define INTC_SIR_IRQ_SPURIOUSIRQ_SHIFT (0x00000007u)
#define INTC_SIR_IRQ_ACTIVEIRQ (0x0000007F)
#define INTC_SIR_IRQ_ACTIVEIRQ_SHIFT (0x00000000)
/* SIR_FIQ */
#define INTC_SIR_FIQ_SPURIOUSFIQ (0xFFFFFF80)
#define INTC_SIR_FIQ_SPURIOUSFIQ_SHIFT (0x00000007)
#define INTC_SIR_FIQ_ACTIVEFIQ (0x0000007F)
#define INTC_SIR_FIQ_ACTIVEFIQ_SHIFT (0x00000000)
/* CONTROL */
#define INTC_CONTROL_NEWFIQAGR (0x00000002)
#define INTC_CONTROL_NEWFIQAGR_SHIFT (0x00000001)
#define INTC_CONTROL_NEWIRQAGR (0x00000001)
#define INTC_CONTROL_NEWIRQAGR_SHIFT (0x00000000)
/* PROTECTION */
#define INTC_PROTECTION_PROTECTION (0x00000001u)
#define INTC_PROTECTION_PROTECTION_SHIFT (0x00000000u)
/* IDLE */
#define INTC_IDLE_TURBO (0x00000002u)
#define INTC_IDLE_TURBO_SHIFT (0x00000001u)
#define INTC_IDLE_FUNCIDLE (0x00000001u)
#define INTC_IDLE_FUNCIDLE_SHIFT (0x00000000u)
/* IRQ_PRIORITY */
#define INTC_IRQ_PRIORITY_SPURIOUSIRQFLAG (0xFFFFFFC0u)
#define INTC_IRQ_PRIORITY_SPURIOUSIRQFLAG_SHIFT (0x00000006u)
#define INTC_IRQ_PRIORITY_IRQPRIORITY (0x0000003Fu)
#define INTC_IRQ_PRIORITY_IRQPRIORITY_SHIFT (0x00000000u)
/* FIQ_PRIORITY */
#define INTC_FIQ_PRIORITY_SPURIOUSFIQFLAG (0xFFFFFFC0u)
#define INTC_FIQ_PRIORITY_SPURIOUSFIQFLAG_SHIFT (0x00000006u)
#define INTC_FIQ_PRIORITY_FIQPRIORITY (0x0000003Fu)
#define INTC_FIQ_PRIORITY_FIQPRIORITY_SHIFT (0x00000000u)
/* THRESHOLD */
#define INTC_THRESHOLD_PRIORITYTHRESHOLD (0x000000FFu)
#define INTC_THRESHOLD_PRIORITYTHRESHOLD_SHIFT (0x00000000u)
/* SICR */
#define INTC_SICR_GLOBALMASK (0x00000040u)
#define INTC_SICR_GLOBALMASK_SHIFT (0x00000006u)
#define INTC_SICR_SOFTRESETINH (0x00000020u)
#define INTC_SICR_SOFTRESETINH_SHIFT (0x00000005u)
#define INTC_SICR_PUBLICMASKFEEDBACK (0x00000010u)
#define INTC_SICR_PUBLICMASKFEEDBACK_SHIFT (0x00000004u)
#define INTC_SICR_PUBLICINHIBIT (0x00000008u)
#define INTC_SICR_PUBLICINHIBIT_SHIFT (0x00000003u)
#define INTC_SICR_AUTOINHIBIT (0x00000004u)
#define INTC_SICR_AUTOINHIBIT_SHIFT (0x00000002u)
#define INTC_SICR_SSMFIQENABLE (0x00000002u)
#define INTC_SICR_SSMFIQENABLE_SHIFT (0x00000001u)
#define INTC_SICR_SSMFIQSTATUS (0x00000001u)
#define INTC_SICR_SSMFIQSTATUS_SHIFT (0x00000000u)
/* SCR0 */
#define INTC_SCR0_SECUREENABLE (0xFFFFFFFFu)
#define INTC_SCR0_SECUREENABLE_SHIFT (0x00000000u)
/* SCR1 */
#define INTC_SCR1_SECUREENABLE (0xFFFFFFFFu)
#define INTC_SCR1_SECUREENABLE_SHIFT (0x00000000u)
/* SCR2 */
#define INTC_SCR2_SECUREENABLE (0xFFFFFFFFu)
#define INTC_SCR2_SECUREENABLE_SHIFT (0x00000000u)
/* ITR0 */
#define INTC_ITR0_ITR (0xFFFFFFFFu)
#define INTC_ITR0_ITR_SHIFT (0x00000000u)
/* MIR0 */
#define INTC_MIR0_MIR (0xFFFFFFFFu)
#define INTC_MIR0_MIR_SHIFT (0x00000000u)
/* MIR_CLEAR0 */
#define INTC_MIR_CLEAR0_MIRCLEAR (0xFFFFFFFFu)
#define INTC_MIR_CLEAR0_MIRCLEAR_SHIFT (0x00000000u)
/* MIR_SET0 */
#define INTC_MIR_SET0_MIRSET (0xFFFFFFFFu)
#define INTC_MIR_SET0_MIRSET_SHIFT (0x00000000u)
/* ISR_SET0 */
#define INTC_ISR_SET0_ISRSET (0xFFFFFFFFu)
#define INTC_ISR_SET0_ISRSET_SHIFT (0x00000000u)
/* ISR_CLEAR0 */
#define INTC_ISR_CLEAR0_ISRCLEAR (0xFFFFFFFFu)
#define INTC_ISR_CLEAR0_ISRCLEAR_SHIFT (0x00000000u)
/* PENDING_IRQ0 */
#define INTC_PENDING_IRQ0_PENDING_IRQ (0xFFFFFFFFu)
#define INTC_PENDING_IRQ0_PENDING_IRQ_SHIFT (0x00000000u)
/* PENDING_FIQ0 */
#define INTC_PENDING_FIQ0_PENDING_FIQ (0xFFFFFFFFu)
#define INTC_PENDING_FIQ0_PENDING_FIQ_SHIFT (0x00000000u)
/* ITR1 */
#define INTC_ITR1_ITR (0xFFFFFFFFu)
#define INTC_ITR1_ITR_SHIFT (0x00000000u)
/* MIR1 */
#define INTC_MIR1_MIR (0xFFFFFFFFu)
#define INTC_MIR1_MIR_SHIFT (0x00000000u)
/* MIR_CLEAR1 */
#define INTC_MIR_CLEAR1_MIRCLEAR (0xFFFFFFFFu)
#define INTC_MIR_CLEAR1_MIRCLEAR_SHIFT (0x00000000u)
/* MIR_SET1 */
#define INTC_MIR_SET1_MIRSET (0xFFFFFFFFu)
#define INTC_MIR_SET1_MIRSET_SHIFT (0x00000000u)
/* ISR_SET1 */
#define INTC_ISR_SET1_ISRSET (0xFFFFFFFFu)
#define INTC_ISR_SET1_ISRSET_SHIFT (0x00000000u)
/* ISR_CLEAR1 */
#define INTC_ISR_CLEAR1_ISRCLEAR (0xFFFFFFFFu)
#define INTC_ISR_CLEAR1_ISRCLEAR_SHIFT (0x00000000u)
/* PENDING_IRQ1 */
#define INTC_PENDING_IRQ1_PENDING_IRQ (0xFFFFFFFFu)
#define INTC_PENDING_IRQ1_PENDING_IRQ_SHIFT (0x00000000u)
/* PENDING_FIQ1 */
#define INTC_PENDING_FIQ1_PENDING_FIQ (0xFFFFFFFFu)
#define INTC_PENDING_FIQ1_PENDING_FIQ_SHIFT (0x00000000u)
/* ITR2 */
#define INTC_ITR2_ITR (0xFFFFFFFFu)
#define INTC_ITR2_ITR_SHIFT (0x00000000u)
/* MIR2 */
#define INTC_MIR2_MIR (0xFFFFFFFFu)
#define INTC_MIR2_MIR_SHIFT (0x00000000u)
/* MIR_CLEAR2 */
#define INTC_MIR_CLEAR2_MIRCLEAR (0xFFFFFFFFu)
#define INTC_MIR_CLEAR2_MIRCLEAR_SHIFT (0x00000000u)
/* MIR_SET2 */
#define INTC_MIR_SET2_MIRSET (0xFFFFFFFFu)
#define INTC_MIR_SET2_MIRSET_SHIFT (0x00000000u)
/* ISR_SET2 */
#define INTC_ISR_SET2_ISRSET (0xFFFFFFFFu)
#define INTC_ISR_SET2_ISRSET_SHIFT (0x00000000u)
/* ISR_CLEAR2 */
#define INTC_ISR_CLEAR2_ISRCLEAR (0xFFFFFFFFu)
#define INTC_ISR_CLEAR2_ISRCLEAR_SHIFT (0x00000000u)
/* PENDING_IRQ2 */
#define INTC_PENDING_IRQ2_PENDING_IRQ (0xFFFFFFFFu)
#define INTC_PENDING_IRQ2_PENDING_IRQ_SHIFT (0x00000000u)
/* PENDING_FIQ2 */
#define INTC_PENDING_FIQ2_PENDING_FIQ (0xFFFFFFFFu)
#define INTC_PENDING_FIQ2_PENDING_FIQ_SHIFT (0x00000000u)
/* ILR */
#define INTC_ILR_PRIORITY (0x000001FCu)
#define INTC_ILR_PRIORITY_SHIFT (0x00000002u)
#define INTC_ILR_FIQNIRQ (0x00000001u)
#define INTC_ILR_FIQNIRQ_SHIFT (0x00000000u)
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

View File

@@ -0,0 +1,189 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-10 bernard porting to AM1808
*/
#include <rtthread.h>
#include "am33xx.h"
#include <mmu.h>
extern void rt_cpu_dcache_disable(void);
extern void rt_hw_cpu_dcache_enable(void);
extern void rt_cpu_icache_disable(void);
extern void rt_hw_cpu_icache_enable(void);
extern void rt_cpu_mmu_disable(void);
extern void rt_cpu_mmu_enable(void);
extern void rt_cpu_tlb_set(register rt_uint32_t i);
void mmu_disable_dcache()
{
rt_cpu_dcache_disable();
}
void mmu_enable_dcache()
{
rt_hw_cpu_dcache_enable();
}
void mmu_disable_icache()
{
rt_cpu_icache_disable();
}
void mmu_enable_icache()
{
rt_hw_cpu_icache_enable();
}
void mmu_disable()
{
rt_cpu_mmu_disable();
}
void mmu_enable()
{
rt_cpu_mmu_enable();
}
void mmu_setttbase(register rt_uint32_t i)
{
register rt_uint32_t value;
/* Invalidates all TLBs.Domain access is selected as
* client by configuring domain access register,
* in that case access controlled by permission value
* set by page table entry
*/
value = 0;
asm volatile ("mcr p15, 0, %0, c8, c7, 0"::"r"(value));
value = 0x55555555;
asm volatile ("mcr p15, 0, %0, c3, c0, 0"::"r"(value));
rt_cpu_tlb_set(i);
}
void mmu_set_domain(register rt_uint32_t i)
{
asm volatile ("mcr p15,0, %0, c3, c0, 0": :"r" (i));
}
void mmu_enable_alignfault()
{
register rt_uint32_t i;
/* read control register */
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i |= (1 << 1);
/* write back to control register */
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
}
void mmu_disable_alignfault()
{
register rt_uint32_t i;
/* read control register */
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i &= ~(1 << 1);
/* write back to control register */
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
}
void mmu_clean_invalidated_cache_index(int index)
{
asm volatile ("mcr p15, 0, %0, c7, c14, 2": :"r" (index));
}
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~0x1f;
while (ptr < buffer + size)
{
asm volatile ("mcr p15, 0, %0, c7, c10, 1": :"r" (ptr));
ptr += 32;
}
}
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~0x1f;
while (ptr < buffer + size)
{
asm volatile ("mcr p15, 0, %0, c7, c6, 1": :"r" (ptr));
ptr += 32;
}
}
void mmu_invalidate_tlb()
{
asm volatile ("mcr p15, 0, %0, c8, c7, 0": :"r" (0));
}
void mmu_invalidate_icache()
{
asm volatile ("mcr p15, 0, %0, c7, c5, 0": :"r" (0));
}
/* level1 page table */
static volatile unsigned int _page_table[4*1024] __attribute__((aligned(16*1024)));
void mmu_setmtt(rt_uint32_t vaddrStart, rt_uint32_t vaddrEnd, rt_uint32_t paddrStart, rt_uint32_t attr)
{
volatile rt_uint32_t *pTT;
int i,nSec;
pTT=(rt_uint32_t *)_page_table+(vaddrStart>>20);
nSec=(vaddrEnd>>20)-(vaddrStart>>20);
for(i=0;i<=nSec;i++)
{
*pTT = attr |(((paddrStart>>20)+i)<<20);
pTT++;
}
}
/* set page table */
rt_weak void mmu_setmtts(void)
{
mmu_setmtt(0x00000000, 0xFFFFFFFF, 0x00000000, RW_NCNB); /* None cached for 4G memory */
mmu_setmtt(0x80200000, 0x80800000 - 1, 0x80200000, RW_CB); /* 126M cached DDR memory */
mmu_setmtt(0x80000000, 0x80200000 - 1, 0x80000000, RW_NCNB); /* 2M none-cached DDR memory */
mmu_setmtt(0x402F0000, 0x40300000 - 1, 0x402F0000, RW_CB); /* 63K OnChip memory */
}
void rt_hw_mmu_init(void)
{
/* disable I/D cache */
mmu_disable_dcache();
mmu_disable_icache();
mmu_disable();
mmu_invalidate_tlb();
mmu_setmtts();
/* set MMU table address */
mmu_setttbase((rt_uint32_t)_page_table);
/* enables MMU */
mmu_enable();
/* enable Instruction Cache */
mmu_enable_icache();
/* enable Data Cache */
mmu_enable_dcache();
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-10 bernard porting to AM1808
*/
#ifndef __MMU_H__
#define __MMU_H__
#include <rtthread.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 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)
#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) /* Read/Write, cache, write back */
#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) /* Read/Write, cache, write through */
#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
void rt_hw_mmu_init(void);
#endif

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-09-23 Bernard the first version
* 2011-10-05 Bernard add thumb mode
*/
#include <rtthread.h>
#include "am33xx.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;
stack_addr += sizeof(rt_uint32_t);
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
stk = (rt_uint32_t *)stack_addr;
*(--stk) = (rt_uint32_t)tentry; /* entry point */
*(--stk) = (rt_uint32_t)texit; /* lr */
*(--stk) = 0xdeadbeef; /* r12 */
*(--stk) = 0xdeadbeef; /* r11 */
*(--stk) = 0xdeadbeef; /* r10 */
*(--stk) = 0xdeadbeef; /* r9 */
*(--stk) = 0xdeadbeef; /* r8 */
*(--stk) = 0xdeadbeef; /* r7 */
*(--stk) = 0xdeadbeef; /* r6 */
*(--stk) = 0xdeadbeef; /* r5 */
*(--stk) = 0xdeadbeef; /* r4 */
*(--stk) = 0xdeadbeef; /* r3 */
*(--stk) = 0xdeadbeef; /* r2 */
*(--stk) = 0xdeadbeef; /* 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;
}
/*@}*/

View File

@@ -0,0 +1,252 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-05 Bernard the first version
*/
.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
.equ UND_Stack_Size, 0x00000200
.equ SVC_Stack_Size, 0x00000100
.equ ABT_Stack_Size, 0x00000000
.equ FIQ_Stack_Size, 0x00000000
.equ IRQ_Stack_Size, 0x00000100
.equ USR_Stack_Size, 0x00000100
#define ISR_Stack_Size (UND_Stack_Size + SVC_Stack_Size + ABT_Stack_Size + \
FIQ_Stack_Size + IRQ_Stack_Size)
/* stack */
.globl stack_start
.globl stack_top
.align 3
stack_start:
.rept ISR_Stack_Size
.long 0
.endr
stack_top:
/* reset entry */
.globl _reset
_reset:
/* 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 */
/* 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 */
ldr pc, _rtthread_startup
_rtthread_startup:
.word rtthread_startup
stack_setup:
ldr r0, =stack_top
@ 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
@ Enter FIQ Mode and set its Stack Pointer
msr cpsr_c, #Mode_FIQ|I_Bit|F_Bit
mov sp, r0
sub r0, r0, #FIQ_Stack_Size
@ Enter IRQ Mode and set its Stack Pointer
msr cpsr_c, #Mode_IRQ|I_Bit|F_Bit
mov sp, r0
sub r0, r0, #IRQ_Stack_Size
@ Enter Supervisor Mode and set its Stack Pointer
msr cpsr_c, #Mode_SVC|I_Bit|F_Bit
mov sp, r0
sub r0, r0, #SVC_Stack_Size
@ Enter User Mode and set its Stack Pointer
mov sp, r0
sub sl, sp, #USR_Stack_Size
bx lr
/* exception handlers: undef, swi, padt, dabt, resv, irq, fiq */
.align 5
.globl vector_undef
vector_undef:
sub sp, sp, #72
stmia sp, {r0 - r12} @/* Calling r0-r12 */
add r8, sp, #60
mrs r1, cpsr
mrs r2, spsr
orr r2,r2, #I_Bit|F_Bit
msr cpsr_c, r2
mov r0, r0
stmdb r8, {sp, lr} @/* Calling SP, LR */
msr cpsr_c, r1 @/* return to Undefined Instruction mode */
str lr, [r8, #0] @/* Save calling PC */
mrs r6, spsr
str r6, [r8, #4] @/* Save CPSR */
str r0, [r8, #8] @/* Save OLD_R0 */
mov r0, sp
bl rt_hw_trap_udef
ldmia sp, {r0 - r12} @/* Calling r0 - r2 */
mov r0, r0
ldr lr, [sp, #60] @/* Get PC */
add sp, sp, #72
movs pc, lr @/* return & move spsr_svc into cpsr */
.align 5
.globl vector_swi
vector_swi:
bl rt_hw_trap_swi
.align 5
.globl vector_pabt
vector_pabt:
bl rt_hw_trap_pabt
.align 5
.globl vector_dabt
vector_dabt:
sub sp, sp, #72
stmia sp, {r0 - r12} @/* Calling r0-r12 */
add r8, sp, #60
stmdb r8, {sp, lr} @/* Calling SP, LR */
str lr, [r8, #0] @/* Save calling PC */
mrs r6, spsr
str r6, [r8, #4] @/* Save CPSR */
str r0, [r8, #8] @/* Save OLD_R0 */
mov r0, sp
bl rt_hw_trap_dabt
ldmia sp, {r0 - r12} @/* Calling r0 - r2 */
mov r0, r0
ldr lr, [sp, #60] @/* Get PC */
add sp, sp, #72
movs pc, lr @/* return & move spsr_svc into cpsr */
.align 5
.globl vector_resv
vector_resv:
b .
.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
.globl vector_irq
vector_irq:
stmfd sp!, {r0-r12,lr}
bl rt_interrupt_enter
bl rt_hw_trap_irq
bl rt_interrupt_leave
@ 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
ldmfd sp!, {r0-r12,lr}
subs pc, lr, #4
rt_hw_context_switch_interrupt_do:
mov r1, #0 @ clear flag
str r1, [r0]
ldmfd sp!, {r0-r12,lr}@ reload saved registers
stmfd sp, {r0-r2} @ save r0-r2
mrs r0, spsr @ get cpsr of interrupt thread
sub r1, sp, #4*3
sub r2, lr, #4 @ save old task's pc to r2
@ switch to SVC mode with no interrupt
msr cpsr_c, #I_Bit|F_Bit|Mode_SVC
stmfd sp!, {r2} @ push old task's pc
stmfd sp!, {r3-r12,lr}@ push old task's lr,r12-r4
ldmfd r1, {r1-r3} @ restore r0-r2 of the interrupt thread
stmfd sp!, {r1-r3} @ push old task's r0-r2
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
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

View File

@@ -0,0 +1,278 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-04-06 zchong the first version
*/
MODULE ?cstartup
; --------------------
; Mode, correspords to bits 0-5 in CPSR
MODE_MSK DEFINE 0x1F ; Bit mask for mode bits in CPSR
I_Bit DEFINE 0x80 ; when I bit is set, IRQ is disabled
F_Bit DEFINE 0x40 ; when F bit is set, FIQ is disabled
USR_MODE DEFINE 0x10 ; User mode
FIQ_MODE DEFINE 0x11 ; Fast Interrupt Request mode
IRQ_MODE DEFINE 0x12 ; Interrupt Request mode
SVC_MODE DEFINE 0x13 ; Supervisor mode
ABT_MODE DEFINE 0x17 ; Abort mode
UND_MODE DEFINE 0x1B ; Undefined Instruction mode
SYS_MODE DEFINE 0x1F ; System mode
;; Forward declaration of sections.
SECTION IRQ_STACK:DATA:NOROOT(3)
SECTION FIQ_STACK:DATA:NOROOT(3)
SECTION SVC_STACK:DATA:NOROOT(3)
SECTION ABT_STACK:DATA:NOROOT(3)
SECTION UND_STACK:DATA:NOROOT(3)
SECTION CSTACK:DATA:NOROOT(3)
SECTION .text:CODE
SECTION .intvec:CODE:NOROOT(5)
PUBLIC __vector
PUBLIC __iar_program_start
__iar_init$$done: ; The vector table is not needed
; until after copy initialization is done
__vector: ; Make this a DATA label, so that stack usage
; analysis doesn't consider it an uncalled fun
ARM
; All default exception handlers (except reset) are
; defined as weak symbol definitions.
; If a handler is defined by the application it will take precedence.
LDR PC,Reset_Addr ; Reset
LDR PC,Undefined_Addr ; Undefined instructions
LDR PC,SWI_Addr ; Software interrupt (SWI/SVC)
LDR PC,Prefetch_Addr ; Prefetch abort
LDR PC,Abort_Addr ; Data abort
DCD 0 ; RESERVED
LDR PC,IRQ_Addr ; IRQ
LDR PC,FIQ_Addr ; FIQ
DATA
Reset_Addr: DCD __iar_program_start
Undefined_Addr: DCD Undefined_Handler
SWI_Addr: DCD SWI_Handler
Prefetch_Addr: DCD Prefetch_Handler
Abort_Addr: DCD Abort_Handler
IRQ_Addr: DCD IRQ_Handler
FIQ_Addr: DCD FIQ_Handler
; --------------------------------------------------
; ?cstartup -- low-level system initialization code.
;
; After a reset execution starts here, the mode is ARM, supervisor
; with interrupts disabled.
;
SECTION .text:CODE:NOROOT(2)
EXTERN rt_hw_trap_udef
EXTERN rt_hw_trap_swi
EXTERN rt_hw_trap_pabt
EXTERN rt_hw_trap_dabt
EXTERN rt_hw_trap_fiq
EXTERN rt_hw_trap_irq
EXTERN rt_interrupt_enter
EXTERN rt_interrupt_leave
EXTERN rt_thread_switch_interrupt_flag
EXTERN rt_interrupt_from_thread
EXTERN rt_interrupt_to_thread
EXTERN rt_current_thread
EXTERN vmm_thread
EXTERN vmm_virq_check
EXTERN __cmain
REQUIRE __vector
EXTWEAK __iar_init_core
EXTWEAK __iar_init_vfp
ARM
__iar_program_start:
?cstartup:
;
; Add initialization needed before setup of stackpointers here.
;
;
; Initialize the stack pointers.
; The pattern below can be used for any of the exception stacks:
; FIQ, IRQ, SVC, ABT, UND, SYS.
; The USR mode uses the same stack as SYS.
; The stack segments must be defined in the linker command file,
; and be declared above.
;
MRS r0, cpsr ; Original PSR value
;; Set up the interrupt stack pointer.
BIC r0, r0, #MODE_MSK ; Clear the mode bits
ORR r0, r0, #IRQ_MODE ; Set IRQ mode bits
MSR cpsr_c, r0 ; Change the mode
LDR sp, =SFE(IRQ_STACK) ; End of IRQ_STACK
BIC sp,sp,#0x7 ; Make sure SP is 8 aligned
;; Set up the fast interrupt stack pointer.
BIC r0, r0, #MODE_MSK ; Clear the mode bits
ORR r0, r0, #FIQ_MODE ; Set FIR mode bits
MSR cpsr_c, r0 ; Change the mode
LDR sp, =SFE(FIQ_STACK) ; End of FIQ_STACK
BIC sp,sp,#0x7 ; Make sure SP is 8 aligned
BIC r0,r0,#MODE_MSK ; Clear the mode bits
ORR r0,r0,#ABT_MODE ; Set Abort mode bits
MSR cpsr_c,r0 ; Change the mode
LDR sp,=SFE(ABT_STACK) ; End of ABT_STACK
BIC sp,sp,#0x7 ; Make sure SP is 8 aligned
BIC r0,r0,#MODE_MSK ; Clear the mode bits
ORR r0,r0,#UND_MODE ; Set Undefined mode bits
MSR cpsr_c,r0 ; Change the mode
LDR sp,=SFE(UND_STACK) ; End of UND_STACK
BIC sp,sp,#0x7 ; Make sure SP is 8 aligned
;; Set up the normal stack pointer.
BIC r0 ,r0, #MODE_MSK ; Clear the mode bits
ORR r0 ,r0, #SVC_MODE ; Set System mode bits
MSR cpsr_c, r0 ; Change the mode
LDR sp, =SFE(SVC_STACK) ; End of SVC_STACK
BIC sp,sp,#0x7 ; Make sure SP is 8 aligned
;; Turn on core features assumed to be enabled.
BL __iar_init_core
;; Initialize VFP (if needed).
BL __iar_init_vfp
;; Continue to __cmain for C-level initialization.
B __cmain
Undefined_Handler:
SUB sp, sp, #72
STMIA sp, {r0 - r12} ;/* Calling r0-r12 */
ADD r8, sp, #60
MRS r1, cpsr
MRS r2, spsr
ORR r2,r2, #I_Bit | F_Bit
MSR cpsr_c, r2
MOV r0, r0
STMDB r8, {sp, lr} ;/* Calling SP, LR */
MSR cpsr_c, r1 ;/* return to Undefined Instruction mode */
STR lr, [r8, #0] ;/* Save calling PC */
MRS r6, spsr
STR r6, [r8, #4] ;/* Save CPSR */
STR r0, [r8, #8] ;/* Save OLD_R0 */
MOV r0, sp
BL rt_hw_trap_udef
LDMIA sp, {r0 - r12} ;/* Calling r0 - r2 */
MOV r0, r0
LDR lr, [sp, #60] ;/* Get PC */
ADD sp, sp, #72
MOVS pc, lr ;/* return & move spsr_svc into cpsr */
SWI_Handler:
BL rt_hw_trap_swi
Prefetch_Handler:
BL rt_hw_trap_pabt
Abort_Handler:
SUB sp, sp, #72
STMIA sp, {r0 - r12} ;/* Calling r0-r12 */
ADD r8, sp, #60
STMDB r8, {sp, lr} ;/* Calling SP, LR */
STR lr, [r8, #0] ;/* Save calling PC */
MRS r6, spsr
STR r6, [r8, #4] ;/* Save CPSR */
STR r0, [r8, #8] ;/* Save OLD_R0 */
MOV r0, sp
BL rt_hw_trap_dabt
LDMIA sp, {r0 - r12} ;/* Calling r0 - r2 */
MOV r0, r0
LDR lr, [sp, #60] ;/* Get PC */
ADD sp, sp, #72
MOVS pc, lr ;/* return & move spsr_svc into cpsr */
FIQ_Handler:
STMFD sp!,{r0-r7,lr}
BL rt_hw_trap_fiq
LDMFD sp!,{r0-r7,lr}
SUBS pc,lr,#4
IRQ_Handler:
STMFD sp!, {r0-r12,lr}
BL rt_interrupt_enter
BL rt_hw_trap_irq
BL rt_interrupt_leave
; 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
LDMFD sp!, {r0-r12,lr}
SUBS pc, lr, #4
rt_hw_context_switch_interrupt_do:
MOV r1, #0 ; clear flag
STR r1, [r0]
LDMFD sp!, {r0-r12,lr}; reload saved registers
STMFD sp, {r0-r2} ; save r0-r2
MRS r0, spsr ; get cpsr of interrupt thread
SUB r1, sp, #4*3
SUB r2, lr, #4 ; save old task's pc to r2
; switch to SVC mode with no interrupt
MSR cpsr_c, #I_Bit | F_Bit | SVC_MODE
STMFD sp!, {r2} ; push old task's pc
STMFD sp!, {r3-r12,lr}; push old task's lr,r12-r4
LDMFD r1, {r1-r3} ; restore r0-r2 of the interrupt thread
STMFD sp!, {r1-r3} ; push old task's r0-r2
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
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
END

View File

@@ -0,0 +1,196 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-09-23 Bernard first version
*/
#include <rtthread.h>
#include <rthw.h>
#include "am33xx.h"
#include "interrupt.h"
#ifdef RT_USING_GDB
#include "gdb_stub.h"
#endif
/**
* @addtogroup AM33XX
*/
/*@{*/
extern struct rt_thread *rt_current_thread;
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
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_register *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 ARM7TDMI 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_udef(struct rt_hw_register *regs)
{
#ifdef RT_USING_GDB
regs->pc -= 4; //lr in undef is pc + 4
if (gdb_undef_hook(regs))
return;
#endif
rt_hw_show_register(regs);
rt_kprintf("undefined instruction\n");
rt_kprintf("thread %.*s stack:\n", RT_NAME_MAX, rt_current_thread->parent.name);
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
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_register *regs)
{
rt_hw_show_register(regs);
rt_kprintf("software interrupt\n");
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_register *regs)
{
rt_hw_show_register(regs);
rt_kprintf("prefetch abort\n");
rt_kprintf("thread %.*s stack:\n", RT_NAME_MAX, rt_current_thread->parent.name);
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
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_register *regs)
{
#ifdef RT_USING_GDB
if (gdb_mem_fault_handler) {
regs->pc = (unsigned long)gdb_mem_fault_handler;
return;
}
#endif
rt_hw_show_register(regs);
rt_kprintf("data abort\n");
rt_kprintf("thread %.*s stack:\n", RT_NAME_MAX, rt_current_thread->parent.name);
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
list_thread();
#endif
rt_hw_cpu_shutdown();
}
void rt_hw_trap_irq()
{
void *param;
unsigned long ir;
rt_isr_handler_t isr_func;
extern struct rt_irq_desc isr_table[];
ir = rt_hw_interrupt_get_active(INT_IRQ);
if (ir == 127)
{
/* new IRQ generation */
rt_hw_interrupt_ack(INT_IRQ);
ir = rt_hw_interrupt_get_active(INT_IRQ);
if (ir == 127)
{
/* still spurious interrupt, get out */
/*rt_kprintf("still spurious interrupt\n");*/
return;
}
/*rt_kprintf("new IRQ: %d\n", ir);*/
}
/* get interrupt service routine */
isr_func = isr_table[ir].handler;
param = isr_table[ir].param;
/* turn to interrupt service routine */
if (isr_func != RT_NULL)
isr_func(ir, param);
/* new IRQ generation */
rt_hw_interrupt_ack(INT_IRQ);
}
void rt_hw_trap_fiq()
{
void *param;
unsigned long ir;
rt_isr_handler_t isr_func;
extern struct rt_irq_desc isr_table[];
ir = rt_hw_interrupt_get_active(INT_FIQ);
/* get interrupt service routine */
isr_func = isr_table[ir].handler;
param = isr_table[ir].param;
/* turn to interrupt service routine */
isr_func(ir, param);
/* new FIQ generation */
rt_hw_interrupt_ack(INT_FIQ);
}
/*@}*/

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-05 Bernard the first version
*/
.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

View File

@@ -0,0 +1,25 @@
# RT-Thread building script for component
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')
CPPPATH = [cwd]
ASFLAGS = ''
if rtconfig.PLATFORM in ['armcc', 'armclang']:
src += Glob('*_rvds.S')
ASFLAGS = ' --cpreproc'
if rtconfig.PLATFORM in ['gcc']:
src += Glob('*_init.S')
src += Glob('*_gcc.S')
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH, ASFLAGS = ASFLAGS)
Return('group')

View File

@@ -0,0 +1,79 @@
;/*
; * Copyright (c) 2006-2018, RT-Thread Development Team
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Change Logs:
; * Date Author Notes
; * 2011-08-14 weety copy from mini2440
; */
#define NOINT 0xC0
.text
;/*
; * rt_base_t rt_hw_interrupt_disable();
; */
.globl rt_hw_interrupt_disable
rt_hw_interrupt_disable:
MRS R0, CPSR
ORR R1, R0, #NOINT
MSR CPSR_c, R1
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(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
STMFD SP!, {R4} @; push cpsr
STR SP, [R0] @; store sp in preempted tasks tcb
LDR SP, [R1] @; get new task stack pointer
LDMFD SP!, {R4} @; pop new task spsr
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12, LR, PC}^ @; pop new task r0-r12, lr & pc
/*
* 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 cpsr
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12, LR, PC}^ @; pop new task r0-r12, lr & pc
/*
* 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
MOV R3, #1 @; set flag to 1
STR R3, [R2]
LDR R2, =rt_interrupt_from_thread @; set rt_interrupt_from_thread
STR R0, [R2]
_reswitch:
LDR R2, =rt_interrupt_to_thread @; set rt_interrupt_to_thread
STR R1, [R2]
BX LR

View File

@@ -0,0 +1,82 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-08-14 weety copy from mini2440
* 2015-04-15 ArdaFu convert from context_gcc.s
*/
#define NOINT 0xc0
SECTION .text:CODE(6)
/*
* rt_base_t rt_hw_interrupt_disable();
*/
PUBLIC rt_hw_interrupt_disable
rt_hw_interrupt_disable:
MRS R0, CPSR
ORR R1, R0, #NOINT
MSR CPSR_C, R1
MOV PC, LR
/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
PUBLIC rt_hw_interrupt_enable
rt_hw_interrupt_enable:
MSR CPSR_CXSF, R0
MOV PC, LR
/*
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
* r0 --> from
* r1 --> to
*/
PUBLIC 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
STMFD SP!, {R4} ; push cpsr
STR SP, [R0] ; store sp in preempted tasks TCB
LDR SP, [R1] ; get new task stack pointer
LDMFD SP!, {R4} ; pop new task spsr
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc
/*
* void rt_hw_context_switch_to(rt_uint32 to);
* r0 --> to
*/
PUBLIC 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
LDMFD SP!, {R0-R12, LR, PC}^ ; pop new task r0-r12, lr & pc
/*
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
*/
IMPORT rt_thread_switch_interrupt_flag
IMPORT rt_interrupt_from_thread
IMPORT rt_interrupt_to_thread
PUBLIC 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
MOV R3, #1 ; set flag to 1
STR R3, [R2]
LDR R2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
STR R0, [R2]
_reswitch:
LDR R2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
STR R1, [R2]
MOV PC, LR
END

View File

@@ -0,0 +1,91 @@
;/*
; * Copyright (c) 2006-2018, RT-Thread Development Team
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Change Logs:
; * Date Author Notes
; * 2011-08-14 weety copy from mini2440
; */
NOINT EQU 0XC0 ; disable interrupt in psr
AREA |.TEXT|, CODE, READONLY, ALIGN=2
ARM
REQUIRE8
PRESERVE8
;/*
; * rt_base_t rt_hw_interrupt_disable();
; */
rt_hw_interrupt_disable PROC
EXPORT rt_hw_interrupt_disable
MRS R0, CPSR
ORR R1, R0, #NOINT
MSR CPSR_C, R1
BX LR
ENDP
;/*
; * void rt_hw_interrupt_enable(rt_base_t level);
; */
rt_hw_interrupt_enable proc
export rt_hw_interrupt_enable
msr cpsr_c, r0
bx lr
endp
;/*
; * void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
; * r0 --> from
; * r1 --> to
; */
rt_hw_context_switch proc
export 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
stmfd sp!, {r4} ; push cpsr
str sp, [r0] ; store sp in preempted tasks tcb
ldr sp, [r1] ; get new task stack pointer
ldmfd sp!, {r4} ; pop new task spsr
msr spsr_cxsf, r4
ldmfd sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc
endp
;/*
; * void rt_hw_context_switch_to(rt_uint32 to);
; * r0 --> to
; */
rt_hw_context_switch_to proc
export rt_hw_context_switch_to
ldr sp, [r0] ; get new task stack pointer
ldmfd sp!, {r4} ; pop new task spsr
msr spsr_cxsf, r4
ldmfd sp!, {r0-r12, lr, pc}^ ; pop new task r0-r12, lr & pc
endp
;/*
; * void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
; */
import rt_thread_switch_interrupt_flag
import rt_interrupt_from_thread
import rt_interrupt_to_thread
rt_hw_context_switch_interrupt proc
export rt_hw_context_switch_interrupt
ldr r2, =rt_thread_switch_interrupt_flag
ldr r3, [r2]
cmp r3, #1
beq _reswitch
mov r3, #1 ; set flag to 1
str r3, [r2]
ldr r2, =rt_interrupt_from_thread ; set rt_interrupt_from_thread
str r0, [r2]
_reswitch
ldr r2, =rt_interrupt_to_thread ; set rt_interrupt_to_thread
str r1, [r2]
bx lr
endp
end

View File

@@ -0,0 +1,216 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-01-13 weety modified from mini2440
* 2015-04-15 ArdaFu Add code for IAR
*/
#include <rthw.h>
#include <rtthread.h>
#define ICACHE_MASK (rt_uint32_t)(1 << 12)
#define DCACHE_MASK (rt_uint32_t)(1 << 2)
extern void machine_reset(void);
extern void machine_shutdown(void);
#if defined(__GNUC__) || defined(__ICCARM__)
rt_inline rt_uint32_t cp15_rd(void)
{
rt_uint32_t i;
__asm volatile("mrc p15, 0, %0, c1, c0, 0":"=r"(i));
return i;
}
rt_inline void cache_enable(rt_uint32_t bit)
{
__asm volatile(\
"mrc p15,0,r0,c1,c0,0\n\t" \
"orr r0,r0,%0\n\t" \
"mcr p15,0,r0,c1,c0,0" \
: \
: "r"(bit) \
: "memory");
}
rt_inline void cache_disable(rt_uint32_t bit)
{
__asm volatile(\
"mrc p15,0,r0,c1,c0,0\n\t" \
"bic r0,r0,%0\n\t" \
"mcr p15,0,r0,c1,c0,0" \
: \
: "r"(bit) \
: "memory");
}
#endif
#if defined(__CC_ARM)
rt_inline rt_uint32_t cp15_rd(void)
{
rt_uint32_t i;
__asm volatile
{
mrc p15, 0, i, c1, c0, 0
}
return i;
}
rt_inline void cache_enable(rt_uint32_t bit)
{
rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, bit
mcr p15, 0, value, c1, c0, 0
}
}
rt_inline void cache_disable(rt_uint32_t bit)
{
rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, bit
mcr p15, 0, value, c1, c0, 0
}
}
#endif
/**
* enable I-Cache
*
*/
void rt_hw_cpu_icache_enable()
{
cache_enable(ICACHE_MASK);
}
/**
* disable I-Cache
*
*/
void rt_hw_cpu_icache_disable()
{
cache_disable(ICACHE_MASK);
}
/**
* return the status of I-Cache
*
*/
rt_base_t rt_hw_cpu_icache_status()
{
return (cp15_rd() & ICACHE_MASK);
}
/**
* enable D-Cache
*
*/
void rt_hw_cpu_dcache_enable()
{
cache_enable(DCACHE_MASK);
}
/**
* disable D-Cache
*
*/
void rt_hw_cpu_dcache_disable()
{
cache_disable(DCACHE_MASK);
}
/**
* return the status of D-Cache
*
*/
rt_base_t rt_hw_cpu_dcache_status()
{
return (cp15_rd() & DCACHE_MASK);
}
/**
* reset cpu by dog's time-out
*
*/
void rt_hw_cpu_reset()
{
rt_kprintf("Restarting system...\n");
machine_reset();
while (1); /* loop forever and wait for reset to happen */
/* NEVER REACHED */
}
/**
* shutdown CPU
*
*/
void rt_hw_cpu_shutdown(void)
{
rt_base_t level;
rt_kprintf("shutdown...\n");
level = rt_hw_interrupt_disable();
machine_shutdown();
while (level)
{
RT_ASSERT(0);
}
}
#ifdef RT_USING_CPU_FFS
/**
* This function finds the first bit set (beginning with the least significant bit)
* in value and return the index of that bit.
*
* Bits are numbered starting at 1 (the least significant bit). A return value of
* zero from any of these functions means that the argument was zero.
*
* @return return the index of the first bit set. If value is 0, then this function
* shall return 0.
*/
#if defined(__CC_ARM)
int __rt_ffs(int value)
{
register rt_uint32_t x;
if (value == 0)
return value;
__asm
{
rsb x, value, #0
and x, x, value
clz x, x
rsb x, x, #32
}
return x;
}
#elif defined(__GNUC__) || defined(__ICCARM__)
int __rt_ffs(int value)
{
return __builtin_ffs(value);
}
#endif
#endif
/*@}*/

View File

@@ -0,0 +1,13 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef CPUPORT_H__
#define CPUPORT_H__
#endif /*CPUPORT_H__*/

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#include <rthw.h>
#include <rtthread.h>
rt_weak void machine_reset(void)
{
rt_kprintf("reboot system...\n");
rt_hw_interrupt_disable();
while (1);
}
rt_weak void machine_shutdown(void)
{
rt_kprintf("shutdown...\n");
rt_hw_interrupt_disable();
while (1);
}

View File

@@ -0,0 +1,443 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2015-04-15 ArdaFu Add code for IAR
*/
#include "mmu.h"
/*----- Keil -----------------------------------------------------------------*/
#ifdef __CC_ARM
void mmu_setttbase(rt_uint32_t i)
{
register rt_uint32_t value;
/* Invalidates all TLBs.Domain access is selected as
* client by configuring domain access register,
* in that case access controlled by permission value
* set by page table entry
*/
value = 0;
__asm volatile{ mcr p15, 0, value, c8, c7, 0 }
value = 0x55555555;
__asm volatile { mcr p15, 0, value, c3, c0, 0 }
__asm volatile { mcr p15, 0, i, c2, c0, 0 }
}
void mmu_set_domain(rt_uint32_t i)
{
__asm volatile { mcr p15, 0, i, c3, c0, 0 }
}
void mmu_enable()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, #0x01
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_disable()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, #0x01
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_enable_icache()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, #0x1000
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_enable_dcache()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, #0x04
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_disable_icache()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, #0x1000
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_disable_dcache()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, #0x04
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_enable_alignfault()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, #0x02
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_disable_alignfault()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, #0x02
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_clean_invalidated_cache_index(int index)
{
__asm volatile { mcr p15, 0, index, c7, c14, 2 }
}
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
__asm volatile { MCR p15, 0, ptr, c7, c14, 1 }
ptr += CACHE_LINE_SIZE;
}
}
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
__asm volatile { MCR p15, 0, ptr, c7, c10, 1 }
ptr += CACHE_LINE_SIZE;
}
}
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
__asm volatile { MCR p15, 0, ptr, c7, c6, 1 }
ptr += CACHE_LINE_SIZE;
}
}
void mmu_invalidate_tlb()
{
register rt_uint32_t value;
value = 0;
__asm volatile { mcr p15, 0, value, c8, c7, 0 }
}
void mmu_invalidate_icache()
{
register rt_uint32_t value;
value = 0;
__asm volatile { mcr p15, 0, value, c7, c5, 0 }
}
void mmu_invalidate_dcache_all()
{
register rt_uint32_t value;
value = 0;
__asm volatile { mcr p15, 0, value, c7, c6, 0 }
}
/*----- GNU ------------------------------------------------------------------*/
#elif defined(__GNUC__) || defined(__ICCARM__)
void mmu_setttbase(register rt_uint32_t i)
{
register rt_uint32_t value;
/* Invalidates all TLBs.Domain access is selected as
* client by configuring domain access register,
* in that case access controlled by permission value
* set by page table entry
*/
value = 0;
asm volatile("mcr p15, 0, %0, c8, c7, 0"::"r"(value));
value = 0x55555555;
asm volatile("mcr p15, 0, %0, c3, c0, 0"::"r"(value));
asm volatile("mcr p15, 0, %0, c2, c0, 0"::"r"(i));
}
void mmu_set_domain(register rt_uint32_t i)
{
asm volatile("mcr p15,0, %0, c3, c0, 0": :"r"(i));
}
void mmu_enable()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"orr r0, r0, #0x1 \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_disable()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"bic r0, r0, #0x1 \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_enable_icache()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"orr r0, r0, #(1<<12) \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_enable_dcache()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"orr r0, r0, #(1<<2) \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_disable_icache()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"bic r0, r0, #(1<<12) \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_disable_dcache()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"bic r0, r0, #(1<<2) \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_enable_alignfault()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"orr r0, r0, #1 \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_disable_alignfault()
{
asm volatile
(
"mrc p15, 0, r0, c1, c0, 0 \n"
"bic r0, r0, #1 \n"
"mcr p15, 0, r0, c1, c0, 0 \n"
:::"r0"
);
}
void mmu_clean_invalidated_cache_index(int index)
{
asm volatile("mcr p15, 0, %0, c7, c14, 2": :"r"(index));
}
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
asm volatile("mcr p15, 0, %0, c7, c14, 1": :"r"(ptr));
ptr += CACHE_LINE_SIZE;
}
}
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
asm volatile("mcr p15, 0, %0, c7, c10, 1": :"r"(ptr));
ptr += CACHE_LINE_SIZE;
}
}
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
asm volatile("mcr p15, 0, %0, c7, c6, 1": :"r"(ptr));
ptr += CACHE_LINE_SIZE;
}
}
void mmu_invalidate_tlb()
{
asm volatile("mcr p15, 0, %0, c8, c7, 0": :"r"(0));
}
void mmu_invalidate_icache()
{
asm volatile("mcr p15, 0, %0, c7, c5, 0": :"r"(0));
}
void mmu_invalidate_dcache_all()
{
asm volatile("mcr p15, 0, %0, c7, c6, 0": :"r"(0));
}
#endif
/* level1 page table */
#if defined(__ICCARM__)
#pragma data_alignment=(16*1024)
static volatile rt_uint32_t _page_table[4 * 1024];
#else
static volatile rt_uint32_t _page_table[4 * 1024] \
__attribute__((aligned(16 * 1024)));
#endif
void 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 nSec;
int i = 0;
pTT = (rt_uint32_t *)_page_table + (vaddrStart >> 20);
nSec = (vaddrEnd >> 20) - (vaddrStart >> 20);
for (i = 0; i <= nSec; i++)
{
*pTT = attr | (((paddrStart >> 20) + i) << 20);
pTT++;
}
}
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size)
{
/* disable I/D cache */
mmu_disable_dcache();
mmu_disable_icache();
mmu_disable();
mmu_invalidate_tlb();
/* set page table */
for (; size > 0; size--)
{
mmu_setmtt(mdesc->vaddr_start, mdesc->vaddr_end,
mdesc->paddr_start, mdesc->attr);
mdesc++;
}
/* set MMU table address */
mmu_setttbase((rt_uint32_t)_page_table);
/* enables MMU */
mmu_enable();
/* enable Instruction Cache */
mmu_enable_icache();
/* enable Data Cache */
mmu_enable_dcache();
mmu_invalidate_icache();
mmu_invalidate_dcache_all();
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-02-08 RT-Thread the first version
*/
#ifndef __MMU_H__
#define __MMU_H__
#include <rtthread.h>
#define CACHE_LINE_SIZE 32
#define DESC_SEC (0x2|(1<<4))
#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 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)
#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) /* Read/Write, cache, write back */
#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) /* Read/Write, cache, write through */
#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
struct mem_desc
{
rt_uint32_t vaddr_start;
rt_uint32_t vaddr_end;
rt_uint32_t paddr_start;
rt_uint32_t attr;
};
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size);
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size);
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size);
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size);
#endif

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-01-13 weety copy from mini2440
*/
#include <rtthread.h>
/*****************************/
/* CPU Mode */
/*****************************/
#define USERMODE 0x10
#define FIQMODE 0x11
#define IRQMODE 0x12
#define SVCMODE 0x13
#define ABORTMODE 0x17
#define UNDEFMODE 0x1b
#define MODEMASK 0x1f
#define NOINT 0xc0
/**
* 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;
stack_addr += sizeof(rt_uint32_t);
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
stk = (rt_uint32_t *)stack_addr;
*(--stk) = (rt_uint32_t)tentry; /* entry point */
*(--stk) = (rt_uint32_t)texit; /* lr */
*(--stk) = 0xdeadbeef; /* r12 */
*(--stk) = 0xdeadbeef; /* r11 */
*(--stk) = 0xdeadbeef; /* r10 */
*(--stk) = 0xdeadbeef; /* r9 */
*(--stk) = 0xdeadbeef; /* r8 */
*(--stk) = 0xdeadbeef; /* r7 */
*(--stk) = 0xdeadbeef; /* r6 */
*(--stk) = 0xdeadbeef; /* r5 */
*(--stk) = 0xdeadbeef; /* r4 */
*(--stk) = 0xdeadbeef; /* r3 */
*(--stk) = 0xdeadbeef; /* r2 */
*(--stk) = 0xdeadbeef; /* 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;
}

View File

@@ -0,0 +1,306 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-01-13 weety first version
* 2015-04-15 ArdaFu Split from AT91SAM9260 BSP
* 2015-04-21 ArdaFu Remove remap code. Using mmu to map vector table
* 2015-06-04 aozima Align stack address to 8 byte.
*/
.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 MODEMASK, 0x1F
.equ NOINT, 0xC0
.equ I_BIT, 0x80
.equ F_BIT, 0x40
.equ UND_STACK_SIZE, 0x00000100
.equ SVC_STACK_SIZE, 0x00000100
.equ ABT_STACK_SIZE, 0x00000100
.equ FIQ_STACK_SIZE, 0x00000100
.equ IRQ_STACK_SIZE, 0x00000100
.equ SYS_STACK_SIZE, 0x00000100
/*
***************************************
* Interrupt vector table
***************************************
*/
.section .vectors
.code 32
.global 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
_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
/*
***************************************
* Stack and Heap Definitions
***************************************
*/
.section .data
.space UND_STACK_SIZE
.align 3
.global und_stack_start
und_stack_start:
.space ABT_STACK_SIZE
.align 3
.global abt_stack_start
abt_stack_start:
.space FIQ_STACK_SIZE
.align 3
.global fiq_stack_start
fiq_stack_start:
.space IRQ_STACK_SIZE
.align 3
.global irq_stack_start
irq_stack_start:
.skip SYS_STACK_SIZE
.align 3
.global sys_stack_start
sys_stack_start:
.space SVC_STACK_SIZE
.align 3
.global svc_stack_start
svc_stack_start:
/*
***************************************
* Startup Code
***************************************
*/
.section .text
.global reset
reset:
/* Enter svc mode and mask interrupts */
mrs r0, cpsr
bic r0, r0, #MODEMASK
orr r0, r0, #MODE_SVC|NOINT
msr cpsr_cxsf, r0
/* init cpu */
bl cpu_init_crit
/* Call low level init function */
ldr sp, =svc_stack_start
ldr r0, =rt_low_level_init
blx r0
/* init stack */
bl stack_setup
/* clear bss */
mov r0, #0
ldr r1, =__bss_start
ldr r2, =__bss_end
bss_clear_loop:
cmp r1, r2
strlo r0, [r1], #4
blo bss_clear_loop
/* 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 */
ldr pc, _rtthread_startup
_rtthread_startup:
.word rtthread_startup
cpu_init_crit:
/* invalidate I/D caches */
mov r0, #0
mcr p15, 0, r0, c7, c7, 0
mcr p15, 0, r0, c8, c7, 0
/* disable MMU stuff and caches */
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x00002300
bic r0, r0, #0x00000087
orr r0, r0, #0x00000002
orr r0, r0, #0x00001000
mcr p15, 0, r0, c1, c0, 0
bx lr
stack_setup:
/* Setup Stack for each mode */
mrs r0, cpsr
bic r0, r0, #MODEMASK
orr r1, r0, #MODE_UND|NOINT
msr cpsr_cxsf, r1
ldr sp, =und_stack_start
orr r1, r0, #MODE_ABT|NOINT
msr cpsr_cxsf, r1
ldr sp, =abt_stack_start
orr r1, r0, #MODE_IRQ|NOINT
msr cpsr_cxsf, r1
ldr sp, =irq_stack_start
orr r1, r0, #MODE_FIQ|NOINT
msr cpsr_cxsf, r1
ldr sp, =fiq_stack_start
orr r1, r0, #MODE_SYS|NOINT
msr cpsr_cxsf,r1
ldr sp, =sys_stack_start
orr r1, r0, #MODE_SVC|NOINT
msr cpsr_cxsf, r1
ldr sp, =svc_stack_start
bx lr
/*
***************************************
* exception handlers
***************************************
*/
/* Interrupt */
vector_fiq:
stmfd sp!,{r0-r7,lr}
bl rt_hw_trap_fiq
ldmfd sp!,{r0-r7,lr}
subs pc, lr, #4
vector_irq:
stmfd sp!, {r0-r12,lr}
bl rt_interrupt_enter
bl rt_hw_trap_irq
bl rt_interrupt_leave
ldr r0, =rt_thread_switch_interrupt_flag
ldr r1, [r0]
cmp r1, #1
beq rt_hw_context_switch_interrupt_do
ldmfd sp!, {r0-r12,lr}
subs pc, lr, #4
rt_hw_context_switch_interrupt_do:
mov r1, #0
str r1, [r0]
mov r1, sp
add sp, sp, #4*4
ldmfd sp!, {r4-r12,lr}
mrs r0, spsr
sub r2, lr, #4
msr cpsr_c, #I_BIT|F_BIT|MODE_SVC
stmfd sp!, {r2}
stmfd sp!, {r4-r12,lr}
ldmfd r1, {r1-r4}
stmfd sp!, {r1-r4}
stmfd sp!, {r0}
ldr r4, =rt_interrupt_from_thread
ldr r5, [r4]
str sp, [r5]
ldr r6, =rt_interrupt_to_thread
ldr r6, [r6]
ldr sp, [r6]
ldmfd sp!, {r4}
msr spsr_cxsf, r4
ldmfd sp!, {r0-r12,lr,pc}^
/* Exception */
.macro push_svc_reg
sub sp, sp, #17 * 4
stmia sp, {r0 - r12}
mov r0, sp
mrs r6, spsr
str lr, [r0, #15*4]
str r6, [r0, #16*4]
str sp, [r0, #13*4]
str lr, [r0, #14*4]
.endm
vector_swi:
push_svc_reg
bl rt_hw_trap_swi
b .
vector_undef:
push_svc_reg
bl rt_hw_trap_udef
b .
vector_pabt:
push_svc_reg
bl rt_hw_trap_pabt
b .
vector_dabt:
push_svc_reg
bl rt_hw_trap_dabt
b .
vector_resv:
push_svc_reg
bl rt_hw_trap_resv
b .

View File

@@ -0,0 +1,278 @@
;/*
; * Copyright (c) 2006-2018, RT-Thread Development Team
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Change Logs:
; * Date Author Notes
; * 2011-01-13 weety first version
; * 2015-04-15 ArdaFu Split from AT91SAM9260 BSP
; * 2015-04-21 ArdaFu Remove remap code. Using mmu to map vector table
; * 2015-06-04 aozima Align stack address to 8 byte.
; */
#include "rt_low_level_init.h"
#define S_FRAME_SIZE (18*4) ;72
;#define S_SPSR (17*4) ;SPSR
;#define S_CPSR (16*4) ;CPSR
#define S_PC (15*4) ;R15
;#define S_LR (14*4) ;R14
;#define S_SP (13*4) ;R13
;#define S_IP (12*4) ;R12
;#define S_FP (11*4) ;R11
;#define S_R10 (10*4)
;#define S_R9 (9*4)
;#define S_R8 (8*4)
;#define S_R7 (7*4)
;#define S_R6 (6*4)
;#define S_R5 (5*4)
;#define S_R4 (4*4)
;#define S_R3 (3*4)
;#define S_R2 (2*4)
;#define S_R1 (1*4)
;#define S_R0 (0*4)
#define MODE_SYS 0x1F
#define MODE_FIQ 0x11
#define MODE_IRQ 0x12
#define MODE_SVC 0x13
#define MODE_ABT 0x17
#define MODE_UND 0x1B
#define MODEMASK 0x1F
#define NOINT 0xC0
;----------------------- Stack and Heap Definitions ----------------------------
MODULE ?cstartup
SECTION .noinit:DATA:NOROOT(3)
DATA
ALIGNRAM 3
DS8 UND_STK_SIZE
PUBLIC UND_STACK_START
UND_STACK_START:
ALIGNRAM 3
DS8 ABT_STK_SIZE
PUBLIC ABT_STACK_START
ABT_STACK_START:
ALIGNRAM 3
DS8 FIQ_STK_SIZE
PUBLIC FIQ_STACK_START
FIQ_STACK_START:
ALIGNRAM 3
DS8 IRQ_STK_SIZE
PUBLIC IRQ_STACK_START
IRQ_STACK_START:
ALIGNRAM 3
DS8 SYS_STK_SIZE
PUBLIC SYS_STACK_START
SYS_STACK_START:
ALIGNRAM 3
DS8 SVC_STK_SIZE
PUBLIC SVC_STACK_START
SVC_STACK_START:
;--------------Jump vector table------------------------------------------------
SECTION .intvec:CODE:ROOT(2)
ARM
PUBLIC Entry_Point
Entry_Point:
__iar_init$$done: ; The interrupt vector is not needed
; until after copy initialization is done
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
vector_reset:
DC32 Reset_Handler
vector_undef:
DC32 Undef_Handler
vector_swi:
DC32 SWI_Handler
vector_pabt:
DC32 PAbt_Handler
vector_dabt:
DC32 DAbt_Handler
vector_resv:
DC32 Resv_Handler
vector_irq:
DC32 IRQ_Handler
vector_fiq:
DC32 FIQ_Handler
;----------------- Reset Handler -----------------------------------------------
EXTERN rt_low_level_init
EXTERN ?main
PUBLIC __iar_program_start
__iar_program_start:
Reset_Handler:
; Set the cpu to SVC32 mode
MRS R0, CPSR
BIC R0, R0, #MODEMASK
ORR R0, R0, #MODE_SVC|NOINT
MSR CPSR_cxsf, R0
; Set CO-Processor
; little-enddisbale I/D Cache MMU, vector table is 0x00000000
MRC P15, 0, R0, C1, C0, 0 ; Read CP15
LDR R1, =0x00003085 ; set clear bits
BIC R0, R0, R1
MCR P15, 0, R0, C1, C0, 0 ; Write CP15
; Call low level init function,
; disable and clear all IRQs, Init MMU, Init interrupt controller, etc.
LDR SP, =SVC_STACK_START
LDR R0, =rt_low_level_init
BLX R0
Setup_Stack:
; Setup Stack for each mode
MRS R0, CPSR
BIC R0, R0, #MODEMASK
ORR R1, R0, #MODE_UND|NOINT
MSR CPSR_cxsf, R1 ; Undef mode
LDR SP, =UND_STACK_START
ORR R1,R0,#MODE_ABT|NOINT
MSR CPSR_cxsf,R1 ; Abort mode
LDR SP, =ABT_STACK_START
ORR R1,R0,#MODE_IRQ|NOINT
MSR CPSR_cxsf,R1 ; IRQ mode
LDR SP, =IRQ_STACK_START
ORR R1,R0,#MODE_FIQ|NOINT
MSR CPSR_cxsf,R1 ; FIQ mode
LDR SP, =FIQ_STACK_START
ORR R1,R0,#MODE_SYS|NOINT
MSR CPSR_cxsf,R1 ; SYS/User mode
LDR SP, =SYS_STACK_START
ORR R1,R0,#MODE_SVC|NOINT
MSR CPSR_cxsf,R1 ; SVC mode
LDR SP, =SVC_STACK_START
; Enter the C code
LDR R0, =?main
BLX R0
;----------------- Exception Handler -------------------------------------------
IMPORT rt_hw_trap_udef
IMPORT rt_hw_trap_swi
IMPORT rt_hw_trap_pabt
IMPORT rt_hw_trap_dabt
IMPORT rt_hw_trap_resv
IMPORT rt_hw_trap_irq
IMPORT rt_hw_trap_fiq
IMPORT rt_interrupt_enter
IMPORT rt_interrupt_leave
IMPORT rt_thread_switch_interrupt_flag
IMPORT rt_interrupt_from_thread
IMPORT rt_interrupt_to_thread
SECTION .text:CODE:ROOT(2)
ARM
Undef_Handler:
SUB SP, SP, #S_FRAME_SIZE
STMIA SP, {R0 - R12} ; Calling R0-R12
ADD R8, SP, #S_PC
STMDB R8, {SP, LR} ; Calling SP, LR
STR LR, [R8, #0] ; Save calling PC
MRS R6, SPSR
STR R6, [R8, #4] ; Save CPSR
STR R0, [R8, #8] ; Save SPSR
MOV R0, SP
BL rt_hw_trap_udef
SWI_Handler:
BL rt_hw_trap_swi
PAbt_Handler:
BL rt_hw_trap_pabt
DAbt_Handler:
SUB SP, SP, #S_FRAME_SIZE
STMIA SP, {R0 - R12} ; Calling R0-R12
ADD R8, SP, #S_PC
STMDB R8, {SP, LR} ; Calling SP, LR
STR LR, [R8, #0] ; Save calling PC
MRS R6, SPSR
STR R6, [R8, #4] ; Save CPSR
STR R0, [R8, #8] ; Save SPSR
MOV R0, SP
BL rt_hw_trap_dabt
Resv_Handler:
BL rt_hw_trap_resv
IRQ_Handler:
STMFD SP!, {R0-R12,LR}
BL rt_interrupt_enter
BL rt_hw_trap_irq
BL rt_interrupt_leave
; 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
LDMFD SP!, {R0-R12,LR}
SUBS PC, LR, #4
FIQ_Handler:
STMFD SP!, {R0-R7,LR}
BL rt_hw_trap_fiq
LDMFD SP!, {R0-R7,LR}
SUBS PC, LR, #4
;------ void rt_hw_context_switch_interrupt_do(rt_base_t flag) -----------------
rt_hw_context_switch_interrupt_do:
MOV R1, #0 ; Clear flag
STR R1, [R0] ; Save to flag variable
LDMFD SP!, {R0-R12,LR} ; Reload saved registers
STMFD SP, {R0-R2} ; Save R0-R2
SUB R1, SP, #4*3 ; Save old task's SP to R1
SUB R2, LR, #4 ; Save old task's PC to R2
MRS R0, SPSR ; Get CPSR of interrupt thread
MSR CPSR_c, #MODE_SVC|NOINT ; Switch to SVC mode and no interrupt
STMFD SP!, {R2} ; Push old task's PC
STMFD SP!, {R3-R12,LR} ; Push old task's LR,R12-R3
LDMFD R1, {R1-R3}
STMFD SP!, {R1-R3} ; Push old task's R2-R0
STMFD SP!, {R0} ; Push old task's CPSR
LDR R4, =rt_interrupt_from_thread
LDR R5, [R4] ; R5 = stack ptr in old tasks's TCB
STR SP, [R5] ; Store SP in preempted tasks's TCB
LDR R6, =rt_interrupt_to_thread
LDR R6, [R6] ; R6 = stack ptr in new tasks's TCB
LDR SP, [R6] ; Get new task's stack pointer
LDMFD SP!, {R4} ; Pop new task's SPSR
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12,LR,PC}^ ; pop new task's R0-R12,LR & PC SPSR to CPSR
END

View File

@@ -0,0 +1,301 @@
;/*
; * Copyright (c) 2006-2018, RT-Thread Development Team
; *
; * SPDX-License-Identifier: Apache-2.0
; *
; * Change Logs:
; * Date Author Notes
; * 2011-08-14 weety first version
; * 2015-04-15 ArdaFu Split from AT91SAM9260 BSP
; * 2015-04-21 ArdaFu Remove remap code. Using mmu to map vector table
; * 2015-06-04 aozima Align stack address to 8 byte.
; */
UND_STK_SIZE EQU 512
SVC_STK_SIZE EQU 4096
ABT_STK_SIZE EQU 512
IRQ_STK_SIZE EQU 1024
FIQ_STK_SIZE EQU 1024
SYS_STK_SIZE EQU 512
Heap_Size EQU 512
S_FRAME_SIZE EQU (18*4) ;72
S_PC EQU (15*4) ;R15
MODE_USR EQU 0X10
MODE_FIQ EQU 0X11
MODE_IRQ EQU 0X12
MODE_SVC EQU 0X13
MODE_ABT EQU 0X17
MODE_UND EQU 0X1B
MODE_SYS EQU 0X1F
MODEMASK EQU 0X1F
NOINT EQU 0xC0
;----------------------- Stack and Heap Definitions ----------------------------
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem
SPACE UND_STK_SIZE
EXPORT UND_STACK_START
UND_STACK_START
ALIGN 8
SPACE ABT_STK_SIZE
EXPORT ABT_STACK_START
ABT_STACK_START
ALIGN 8
SPACE FIQ_STK_SIZE
EXPORT FIQ_STACK_START
FIQ_STACK_START
ALIGN 8
SPACE IRQ_STK_SIZE
EXPORT IRQ_STACK_START
IRQ_STACK_START
ALIGN 8
SPACE SYS_STK_SIZE
EXPORT SYS_STACK_START
SYS_STACK_START
ALIGN 8
SPACE SVC_STK_SIZE
EXPORT SVC_STACK_START
SVC_STACK_START
Stack_Top
__initial_sp
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8
;--------------Jump vector table------------------------------------------------
EXPORT Entry_Point
AREA RESET, CODE, READONLY
ARM
Entry_Point
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
vector_reset
DCD Reset_Handler
vector_undef
DCD Undef_Handler
vector_swi
DCD SWI_Handler
vector_pabt
DCD PAbt_Handler
vector_dabt
DCD DAbt_Handler
vector_resv
DCD Resv_Handler
vector_irq
DCD IRQ_Handler
vector_fiq
DCD FIQ_Handler
;----------------- Reset Handler -----------------------------------------------
IMPORT rt_low_level_init
IMPORT __main
EXPORT Reset_Handler
Reset_Handler
; set the cpu to SVC32 mode
MRS R0,CPSR
BIC R0,R0,#MODEMASK
ORR R0,R0,#MODE_SVC:OR:NOINT
MSR CPSR_cxsf,R0
; Set CO-Processor
; little-enddisbale I/D Cache MMU, vector table is 0x00000000
MRC p15, 0, R0, c1, c0, 0 ; Read CP15
LDR R1, =0x00003085 ; set clear bits
BIC R0, R0, R1
MCR p15, 0, R0, c1, c0, 0 ; Write CP15
; Call low level init function,
; disable and clear all IRQs, Init MMU, Init interrupt controller, etc.
LDR SP, =SVC_STACK_START
LDR R0, =rt_low_level_init
BLX R0
Setup_Stack
; Setup Stack for each mode
MRS R0, CPSR
BIC R0, R0, #MODEMASK
ORR R1, R0, #MODE_UND:OR:NOINT
MSR CPSR_cxsf, R1 ; Undef mode
LDR SP, =UND_STACK_START
ORR R1,R0,#MODE_ABT:OR:NOINT
MSR CPSR_cxsf,R1 ; Abort mode
LDR SP, =ABT_STACK_START
ORR R1,R0,#MODE_IRQ:OR:NOINT
MSR CPSR_cxsf,R1 ; IRQ mode
LDR SP, =IRQ_STACK_START
ORR R1,R0,#MODE_FIQ:OR:NOINT
MSR CPSR_cxsf,R1 ; FIQ mode
LDR SP, =FIQ_STACK_START
ORR R1,R0,#MODE_SYS:OR:NOINT
MSR CPSR_cxsf,R1 ; SYS/User mode
LDR SP, =SYS_STACK_START
ORR R1,R0,#MODE_SVC:OR:NOINT
MSR CPSR_cxsf,R1 ; SVC mode
LDR SP, =SVC_STACK_START
; Enter the C code
LDR R0, =__main
BLX R0
;----------------- Exception Handler -------------------------------------------
IMPORT rt_hw_trap_udef
IMPORT rt_hw_trap_swi
IMPORT rt_hw_trap_pabt
IMPORT rt_hw_trap_dabt
IMPORT rt_hw_trap_resv
IMPORT rt_hw_trap_irq
IMPORT rt_hw_trap_fiq
IMPORT rt_interrupt_enter
IMPORT rt_interrupt_leave
IMPORT rt_thread_switch_interrupt_flag
IMPORT rt_interrupt_from_thread
IMPORT rt_interrupt_to_thread
Undef_Handler PROC
SUB SP, SP, #S_FRAME_SIZE
STMIA SP, {R0 - R12} ; Calling R0-R12
ADD R8, SP, #S_PC
STMDB R8, {SP, LR} ; Calling SP, LR
STR LR, [R8, #0] ; Save calling PC
MRS R6, SPSR
STR R6, [R8, #4] ; Save CPSR
STR R0, [R8, #8] ; Save SPSR
MOV R0, SP
BL rt_hw_trap_udef
ENDP
SWI_Handler PROC
BL rt_hw_trap_swi
ENDP
PAbt_Handler PROC
BL rt_hw_trap_pabt
ENDP
DAbt_Handler PROC
SUB SP, SP, #S_FRAME_SIZE
STMIA SP, {R0 - R12} ; Calling R0-R12
ADD R8, SP, #S_PC
STMDB R8, {SP, LR} ; Calling SP, LR
STR LR, [R8, #0] ; Save calling PC
MRS R6, SPSR
STR R6, [R8, #4] ; Save CPSR
STR R0, [R8, #8] ; Save SPSR
MOV R0, SP
BL rt_hw_trap_dabt
ENDP
Resv_Handler PROC
BL rt_hw_trap_resv
ENDP
FIQ_Handler PROC
STMFD SP!, {R0-R7,LR}
BL rt_hw_trap_fiq
LDMFD SP!, {R0-R7,LR}
SUBS PC, LR, #4
ENDP
IRQ_Handler PROC
STMFD SP!, {R0-R12,LR}
BL rt_interrupt_enter
BL rt_hw_trap_irq
BL rt_interrupt_leave
; 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
LDMFD SP!, {R0-R12,LR}
SUBS PC, LR, #4
ENDP
;------ void rt_hw_context_switch_interrupt_do(rt_base_t flag) -----------------
rt_hw_context_switch_interrupt_do PROC
MOV R1, #0 ; Clear flag
STR R1, [R0] ; Save to flag variable
LDMFD SP!, {R0-R12,LR} ; Reload saved registers
STMFD SP, {R0-R2} ; Save R0-R2
SUB R1, SP, #4*3 ; Save old task's SP to R1
SUB R2, LR, #4 ; Save old task's PC to R2
MRS R0, SPSR ; Get CPSR of interrupt thread
MSR CPSR_c, #MODE_SVC:OR:NOINT ; Switch to SVC mode and no interrupt
STMFD SP!, {R2} ; Push old task's PC
STMFD SP!, {R3-R12,LR} ; Push old task's LR,R12-R3
LDMFD R1, {R1-R3}
STMFD SP!, {R1-R3} ; Push old task's R2-R0
STMFD SP!, {R0} ; Push old task's CPSR
LDR R4, =rt_interrupt_from_thread
LDR R5, [R4] ; R5 = stack ptr in old tasks's TCB
STR SP, [R5] ; Store SP in preempted tasks's TCB
LDR R6, =rt_interrupt_to_thread
LDR R6, [R6] ; R6 = stack ptr in new tasks's TCB
LDR SP, [R6] ; Get new task's stack pointer
LDMFD SP!, {R4} ; Pop new task's SPSR
MSR SPSR_cxsf, R4
LDMFD SP!, {R0-R12,LR,PC}^ ; pop new task's R0-R12,LR & PC SPSR to CPSR
ENDP
;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, = Heap_Mem ; heap base
LDR R1, = SVC_STACK_START ; stack base (top-address)
LDR R2, = (Heap_Mem + Heap_Size) ; heap limit
LDR R3, = (SVC_STACK_START - SVC_STK_SIZE) ; stack limit (low-address)
BX LR
ALIGN
ENDIF
END

View File

@@ -0,0 +1,210 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-01-13 weety modified from mini2440
* 2015-04-15 ArdaFu Split from AT91SAM9260 BSP
*/
#include <rtthread.h>
#include <rthw.h>
#define INT_IRQ 0x00
#define INT_FIQ 0x01
extern struct rt_thread *rt_current_thread;
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
extern long list_thread(void);
#endif
struct rt_hw_register
{
rt_uint32_t r0;
rt_uint32_t r1;
rt_uint32_t r2;
rt_uint32_t r3;
rt_uint32_t r4;
rt_uint32_t r5;
rt_uint32_t r6;
rt_uint32_t r7;
rt_uint32_t r8;
rt_uint32_t r9;
rt_uint32_t r10;
rt_uint32_t fp;
rt_uint32_t ip;
rt_uint32_t sp;
rt_uint32_t lr;
rt_uint32_t pc;
rt_uint32_t cpsr;
rt_uint32_t ORIG_r0;
};
static rt_err_t (*rt_exception_hook)(void *context) = RT_NULL;
void rt_hw_exception_install(rt_err_t (*exception_handle)(void *context))
{
rt_exception_hook = exception_handle;
}
/**
* this function will show registers of CPU
*
* @param regs the registers point
*/
void rt_hw_show_register(struct rt_hw_register *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 ARM7TDMI 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_udef(struct rt_hw_register *regs)
{
if (rt_exception_hook != RT_NULL)
{
rt_err_t result;
result = rt_exception_hook(regs);
if (result == RT_EOK) return;
}
rt_hw_show_register(regs);
rt_kprintf("undefined instruction\n");
rt_kprintf("thread - %s stack:\n", rt_current_thread->parent.name);
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
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_register *regs)
{
if (rt_exception_hook != RT_NULL)
{
rt_err_t result;
result = rt_exception_hook(regs);
if (result == RT_EOK) return;
}
rt_hw_show_register(regs);
rt_kprintf("software interrupt\n");
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_register *regs)
{
if (rt_exception_hook != RT_NULL)
{
rt_err_t result;
result = rt_exception_hook(regs);
if (result == RT_EOK) return;
}
rt_hw_show_register(regs);
rt_kprintf("prefetch abort\n");
rt_kprintf("thread - %.*s stack:\n", RT_NAME_MAX, rt_current_thread->parent.name);
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
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_register *regs)
{
if (rt_exception_hook != RT_NULL)
{
rt_err_t result;
result = rt_exception_hook(regs);
if (result == RT_EOK) return;
}
rt_hw_show_register(regs);
rt_kprintf("data abort\n");
rt_kprintf("thread - %.*s stack:\n", RT_NAME_MAX, rt_current_thread->parent.name);
#if defined(RT_USING_FINSH) && defined(MSH_USING_BUILT_IN_COMMANDS)
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_register *regs)
{
if (rt_exception_hook != RT_NULL)
{
rt_err_t result;
result = rt_exception_hook(regs);
if (result == RT_EOK) return;
}
rt_kprintf("not used\n");
rt_hw_show_register(regs);
rt_hw_cpu_shutdown();
}
extern void rt_interrupt_dispatch(rt_uint32_t fiq_irq);
void rt_hw_trap_irq(void)
{
rt_interrupt_dispatch(INT_IRQ);
}
void rt_hw_trap_fiq(void)
{
rt_interrupt_dispatch(INT_FIQ);
}

View File

@@ -0,0 +1,23 @@
# RT-Thread building script for component
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')
CPPPATH = [cwd]
if rtconfig.PLATFORM in ['armcc', 'armclang']:
src += Glob('*_rvds.S')
if rtconfig.PLATFORM in ['gcc']:
src += Glob('*_init.S')
src += Glob('*_gcc.S')
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@@ -0,0 +1,126 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2014-11-07 weety first version
*/
#include <rtconfig.h>
#include "armv6.h"
//#define DEBUG
.macro PRINT, str
#ifdef DEBUG
stmfd sp!, {r0-r3, ip, lr}
add r0, pc, #4
bl rt_kprintf
b 1f
.asciz "UNDEF: \str\n"
.balign 4
1: ldmfd sp!, {r0-r3, ip, lr}
#endif
.endm
.macro PRINT1, str, arg
#ifdef DEBUG
stmfd sp!, {r0-r3, ip, lr}
mov r1, \arg
add r0, pc, #4
bl rt_kprintf
b 1f
.asciz "UNDEF: \str\n"
.balign 4
1: ldmfd sp!, {r0-r3, ip, lr}
#endif
.endm
.macro PRINT3, str, arg1, arg2, arg3
#ifdef DEBUG
stmfd sp!, {r0-r3, ip, lr}
mov r3, \arg3
mov r2, \arg2
mov r1, \arg1
add r0, pc, #4
bl rt_kprintf
b 1f
.asciz "UNDEF: \str\n"
.balign 4
1: ldmfd sp!, {r0-r3, ip, lr}
#endif
.endm
.macro get_current_thread, rd
ldr \rd, .current_thread
ldr \rd, [\rd]
.endm
.current_thread:
.word rt_current_thread
#ifdef RT_USING_NEON
.align 6
/* is the neon instuction on arm mode? */
.neon_opcode:
.word 0xfe000000 @ mask
.word 0xf2000000 @ opcode
.word 0xff100000 @ mask
.word 0xf4000000 @ opcode
.word 0x00000000 @ end mask
.word 0x00000000 @ end opcode
#endif
/* undefined instruction exception processing */
.globl undef_entry
undef_entry:
PRINT1 "r0=0x%08x", r0
PRINT1 "r2=0x%08x", r2
PRINT1 "r9=0x%08x", r9
PRINT1 "sp=0x%08x", sp
#ifdef RT_USING_NEON
ldr r6, .neon_opcode
__check_neon_instruction:
ldr r7, [r6], #4 @ load mask value
cmp r7, #0 @ end mask?
beq __check_vfp_instruction
and r8, r0, r7
ldr r7, [r6], #4 @ load opcode value
cmp r8, r7 @ is NEON instruction?
bne __check_neon_instruction
b vfp_entry
__check_vfp_instruction:
#endif
tst r0, #0x08000000 @ only CDP/CPRT/LDC/STC instruction has bit 27
tstne r0, #0x04000000 @ bit 26 set on both ARM and Thumb-2 instruction
moveq pc, lr @ no vfp coprocessor instruction, return
get_current_thread r10
and r8, r0, #0x00000f00 @ get coprocessor number
PRINT1 "CP=0x%08x", r8
add pc, pc, r8, lsr #6
nop
mov pc, lr @ CP0
mov pc, lr @ CP1
mov pc, lr @ CP2
mov pc, lr @ CP3
mov pc, lr @ CP4
mov pc, lr @ CP5
mov pc, lr @ CP6
mov pc, lr @ CP7
mov pc, lr @ CP8
mov pc, lr @ CP9
mov pc, lr @ CP10 VFP
mov pc, lr @ CP11 VFP
mov pc, lr @ CP12
mov pc, lr @ CP13
mov pc, lr @ CP14 DEBUG
mov pc, lr @ CP15 SYS CONTROL

View File

@@ -0,0 +1,93 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef __ARMV6_H__
#define __ARMV6_H__
/*****************************/
/* CPU Mode */
/*****************************/
#define USERMODE 0x10
#define FIQMODE 0x11
#define IRQMODE 0x12
#define SVCMODE 0x13
#define ABORTMODE 0x17
#define UNDEFMODE 0x1b
#define MODEMASK 0x1f
#define NOINT 0xc0
#ifndef __ASSEMBLY__
struct rt_hw_register
{
rt_uint32_t cpsr;
rt_uint32_t r0;
rt_uint32_t r1;
rt_uint32_t r2;
rt_uint32_t r3;
rt_uint32_t r4;
rt_uint32_t r5;
rt_uint32_t r6;
rt_uint32_t r7;
rt_uint32_t r8;
rt_uint32_t r9;
rt_uint32_t r10;
rt_uint32_t fp;
rt_uint32_t ip;
rt_uint32_t sp;
rt_uint32_t lr;
rt_uint32_t pc;
};
#if(0)
struct rt_hw_register{
rt_uint32_t r0;
rt_uint32_t r1;
rt_uint32_t r2;
rt_uint32_t r3;
rt_uint32_t r4;
rt_uint32_t r5;
rt_uint32_t r6;
rt_uint32_t r7;
rt_uint32_t r8;
rt_uint32_t r9;
rt_uint32_t r10;
rt_uint32_t fp;
rt_uint32_t ip;
rt_uint32_t sp;
rt_uint32_t lr;
rt_uint32_t pc;
rt_uint32_t cpsr;
rt_uint32_t ORIG_r0;
};
#endif
#endif
/* rt_hw_register offset */
#define S_FRAME_SIZE 68
#define S_PC 64
#define S_LR 60
#define S_SP 56
#define S_IP 52
#define S_FP 48
#define S_R10 44
#define S_R9 40
#define S_R8 36
#define S_R7 32
#define S_R6 28
#define S_R5 24
#define S_R4 20
#define S_R3 16
#define S_R2 12
#define S_R1 8
#define S_R0 4
#define S_CPSR 0
#endif

View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-01-13 weety copy from mini2440
*/
/*!
* \addtogroup ARMv6
*/
/*@{*/
#include <rtconfig.h>
#define NOINT 0xc0
#define FPEXC_EN (1 << 30) /* VFP enable bit */
/*
* rt_base_t rt_hw_interrupt_disable();
*/
.globl rt_hw_interrupt_disable
rt_hw_interrupt_disable:
mrs r0, cpsr
cpsid if
bx lr
/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
.globl rt_hw_interrupt_enable
rt_hw_interrupt_enable:
msr cpsr_c, r0
bx lr
/*
* 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
ldmfd sp!, {r4} @ pop new task cpsr to spsr
msr spsr_cxsf, r4
_do_switch:
ldmfd sp!, {r0-r12, lr, pc}^ @ pop new task r0-r12, lr & pc, copy spsr to cpsr
/*
* 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
/*
* 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
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
str r3, [r2]
ldr r2, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
str r0, [r2]
_reswitch:
ldr r2, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
str r1, [r2]
bx lr

View File

@@ -0,0 +1,234 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-01-13 weety modified from mini2440
*/
#include <rthw.h>
#include <rtthread.h>
#define ICACHE_MASK (rt_uint32_t)(1 << 12)
#define DCACHE_MASK (rt_uint32_t)(1 << 2)
extern void machine_reset(void);
extern void machine_shutdown(void);
#ifdef __GNUC__
rt_inline rt_uint32_t cp15_rd(void)
{
rt_uint32_t i;
asm ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
return i;
}
rt_inline void cache_enable(rt_uint32_t bit)
{
__asm__ __volatile__( \
"mrc p15,0,r0,c1,c0,0\n\t" \
"orr r0,r0,%0\n\t" \
"mcr p15,0,r0,c1,c0,0" \
: \
:"r" (bit) \
:"memory");
}
rt_inline void cache_disable(rt_uint32_t bit)
{
__asm__ __volatile__( \
"mrc p15,0,r0,c1,c0,0\n\t" \
"bic r0,r0,%0\n\t" \
"mcr p15,0,r0,c1,c0,0" \
: \
:"r" (bit) \
:"memory");
}
#endif
#ifdef __CC_ARM
rt_inline rt_uint32_t cp15_rd(void)
{
rt_uint32_t i;
__asm
{
mrc p15, 0, i, c1, c0, 0
}
return i;
}
rt_inline void cache_enable(rt_uint32_t bit)
{
rt_uint32_t value;
__asm
{
mrc p15, 0, value, c1, c0, 0
orr value, value, bit
mcr p15, 0, value, c1, c0, 0
}
}
rt_inline void cache_disable(rt_uint32_t bit)
{
rt_uint32_t value;
__asm
{
mrc p15, 0, value, c1, c0, 0
bic value, value, bit
mcr p15, 0, value, c1, c0, 0
}
}
#endif
/**
* enable I-Cache
*
*/
void rt_hw_cpu_icache_enable()
{
cache_enable(ICACHE_MASK);
}
/**
* disable I-Cache
*
*/
void rt_hw_cpu_icache_disable()
{
cache_disable(ICACHE_MASK);
}
/**
* return the status of I-Cache
*
*/
rt_base_t rt_hw_cpu_icache_status()
{
return (cp15_rd() & ICACHE_MASK);
}
/**
* enable D-Cache
*
*/
void rt_hw_cpu_dcache_enable()
{
cache_enable(DCACHE_MASK);
}
/**
* disable D-Cache
*
*/
void rt_hw_cpu_dcache_disable()
{
cache_disable(DCACHE_MASK);
}
/**
* return the status of D-Cache
*
*/
rt_base_t rt_hw_cpu_dcache_status()
{
return (cp15_rd() & DCACHE_MASK);
}
/**
* reset cpu by dog's time-out
*
*/
void rt_hw_cpu_reset()
{
rt_kprintf("Restarting system...\n");
machine_reset();
while(1); /* loop forever and wait for reset to happen */
/* NEVER REACHED */
}
/**
* shutdown CPU
*
*/
void rt_hw_cpu_shutdown(void)
{
rt_base_t level;
rt_kprintf("shutdown...\n");
level = rt_hw_interrupt_disable();
machine_shutdown();
while (level)
{
RT_ASSERT(0);
}
}
#ifdef RT_USING_CPU_FFS
/**
* This function finds the first bit set (beginning with the least significant bit)
* in value and return the index of that bit.
*
* Bits are numbered starting at 1 (the least significant bit). A return value of
* zero from any of these functions means that the argument was zero.
*
* @return return the index of the first bit set. If value is 0, then this function
* shall return 0.
*/
#if defined(__CC_ARM)
int __rt_ffs(int value)
{
register rt_uint32_t x;
if (value == 0)
return value;
__asm
{
rsb x, value, #0
and x, x, value
clz x, x
rsb x, x, #32
}
return x;
}
#elif defined(__IAR_SYSTEMS_ICC__)
int __rt_ffs(int value)
{
if (value == 0)
return value;
__ASM("RSB r4, r0, #0");
__ASM("AND r4, r4, r0");
__ASM("CLZ r4, r4");
__ASM("RSB r0, r4, #32");
}
#elif defined(__GNUC__)
int __rt_ffs(int value)
{
if (value == 0)
return value;
value &= (-value);
asm ("clz %0, %1": "=r"(value) :"r"(value));
return (32 - value);
}
#endif
#endif
/*@}*/

View File

@@ -0,0 +1,548 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include "mmu.h"
#ifdef __CC_ARM
void mmu_setttbase(rt_uint32_t i)
{
register rt_uint32_t value;
/* Invalidates all TLBs.Domain access is selected as
* client by configuring domain access register,
* in that case access controlled by permission value
* set by page table entry
*/
value = 0;
__asm volatile
{
mcr p15, 0, value, c8, c7, 0
}
value = 0x55555555;
__asm volatile
{
mcr p15, 0, value, c3, c0, 0
mcr p15, 0, i, c2, c0, 0
}
}
void mmu_set_domain(rt_uint32_t i)
{
__asm volatile
{
mcr p15,0, i, c3, c0, 0
}
}
void mmu_enable()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, #0x01
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_disable()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, #0x01
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_enable_icache()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, #0x1000
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_enable_dcache()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, #0x04
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_disable_icache()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, #0x1000
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_disable_dcache()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, #0x04
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_enable_alignfault()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
orr value, value, #0x02
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_disable_alignfault()
{
register rt_uint32_t value;
__asm volatile
{
mrc p15, 0, value, c1, c0, 0
bic value, value, #0x02
mcr p15, 0, value, c1, c0, 0
}
}
void mmu_clean_invalidated_cache_index(int index)
{
__asm volatile
{
mcr p15, 0, index, c7, c14, 2
}
}
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while(ptr < buffer + size)
{
__asm volatile
{
MCR p15, 0, ptr, c7, c14, 1
}
ptr += CACHE_LINE_SIZE;
}
}
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
__asm volatile
{
MCR p15, 0, ptr, c7, c10, 1
}
ptr += CACHE_LINE_SIZE;
}
}
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
__asm volatile
{
MCR p15, 0, ptr, c7, c6, 1
}
ptr += CACHE_LINE_SIZE;
}
}
void mmu_invalidate_tlb()
{
register rt_uint32_t value;
value = 0;
__asm volatile
{
mcr p15, 0, value, c8, c7, 0
}
}
void mmu_invalidate_icache()
{
register rt_uint32_t value;
value = 0;
__asm volatile
{
mcr p15, 0, value, c7, c5, 0
}
}
void mmu_invalidate_dcache_all()
{
register rt_uint32_t value;
value = 0;
__asm volatile
{
mcr p15, 0, value, c7, c6, 0
}
}
#elif defined(__GNUC__)
void mmu_setttbase(register rt_uint32_t i)
{
register rt_uint32_t value;
/* Invalidates all TLBs.Domain access is selected as
* client by configuring domain access register,
* in that case access controlled by permission value
* set by page table entry
*/
value = 0;
asm volatile ("mcr p15, 0, %0, c8, c7, 0"::"r"(value));
value = 0x55555555;
asm volatile ("mcr p15, 0, %0, c3, c0, 0"::"r"(value));
asm volatile ("mcr p15, 0, %0, c2, c0, 0"::"r"(i));
}
void mmu_set_domain(register rt_uint32_t i)
{
asm volatile ("mcr p15,0, %0, c3, c0, 0": :"r" (i));
}
void mmu_enable()
{
register rt_uint32_t i;
/* read control register */
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i |= 0x1;
/* Enables the extended page tables to be configured for
the hardware page translation mechanism, Subpage AP bits disabled */
i |= (1 << 23); /* support for ARMv6 MMU features */
i |= (1 << 13); /* High exception vectors selected, address range = 0xFFFF0000-0xFFFF001C */
/* write back to control register */
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
}
void mmu_disable()
{
register rt_uint32_t i;
/* read control register */
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i &= ~0x1;
/* write back to control register */
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
}
void mmu_enable_icache()
{
register rt_uint32_t i;
/* read control register */
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i |= (1 << 12);
/* write back to control register */
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
}
void mmu_enable_dcache()
{
register rt_uint32_t i;
/* read control register */
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i |= (1 << 2);
/* write back to control register */
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
}
void mmu_disable_icache()
{
register rt_uint32_t i;
/* read control register */
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i &= ~(1 << 12);
/* write back to control register */
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
}
void mmu_disable_dcache()
{
register rt_uint32_t i;
/* read control register */
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i &= ~(1 << 2);
/* write back to control register */
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
}
void mmu_enable_alignfault()
{
register rt_uint32_t i;
/* read control register */
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i |= (1 << 1);
/* write back to control register */
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
}
void mmu_disable_alignfault()
{
register rt_uint32_t i;
/* read control register */
asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
i &= ~(1 << 1);
/* write back to control register */
asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
}
void mmu_clean_invalidated_cache_index(int index)
{
asm volatile ("mcr p15, 0, %0, c7, c14, 2": :"r" (index));
}
void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while(ptr < buffer + size)
{
asm volatile ("mcr p15, 0, %0, c7, c14, 1": :"r" (ptr));
ptr += CACHE_LINE_SIZE;
}
}
void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
asm volatile ("mcr p15, 0, %0, c7, c10, 1": :"r" (ptr));
ptr += CACHE_LINE_SIZE;
}
}
void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
{
unsigned int ptr;
ptr = buffer & ~(CACHE_LINE_SIZE - 1);
while (ptr < buffer + size)
{
asm volatile ("mcr p15, 0, %0, c7, c6, 1": :"r" (ptr));
ptr += CACHE_LINE_SIZE;
}
}
void mmu_invalidate_tlb()
{
asm volatile ("mcr p15, 0, %0, c8, c7, 0": :"r" (0));
}
void mmu_invalidate_icache()
{
asm volatile ("mcr p15, 0, %0, c7, c5, 0": :"r" (0));
}
void mmu_invalidate_dcache_all()
{
asm volatile ("mcr p15, 0, %0, c7, c6, 0": :"r" (0));
}
#endif
/* level1 page table */
static volatile unsigned int _pgd_table[4*1024] rt_align(16*1024);
/*
* level2 page table
* RT_MMU_PTE_SIZE must be 1024*n
*/
#define RT_MMU_PTE_SIZE 4096
static volatile unsigned int _pte_table[RT_MMU_PTE_SIZE] rt_align(1*1024);
void mmu_create_pgd(struct mem_desc *mdesc)
{
volatile rt_uint32_t *pTT;
volatile int i, nSec;
pTT = (rt_uint32_t *)_pgd_table + (mdesc->vaddr_start >> 20);
nSec = (mdesc->vaddr_end >> 20) - (mdesc->vaddr_start >> 20);
for(i = 0; i <= nSec; i++)
{
*pTT = mdesc->sect_attr | (((mdesc->paddr_start >> 20) + i) << 20);
pTT++;
}
}
void mmu_create_pte(struct mem_desc *mdesc)
{
volatile rt_uint32_t *pTT;
volatile rt_uint32_t *p_pteentry;
int i;
rt_uint32_t vaddr;
rt_uint32_t total_page = 0;
rt_uint32_t pte_offset = 0;
rt_uint32_t sect_attr = 0;
total_page = (mdesc->vaddr_end >> 12) - (mdesc->vaddr_start >> 12) + 1;
pte_offset = mdesc->sect_attr & 0xfffffc00;
sect_attr = mdesc->sect_attr & 0x3ff;
vaddr = mdesc->vaddr_start;
for(i = 0; i < total_page; i++)
{
pTT = (rt_uint32_t *)_pgd_table + (vaddr >> 20);
if (*pTT == 0) /* Level 1 page table item not used, now update pgd item */
{
*pTT = pte_offset | sect_attr;
p_pteentry = (rt_uint32_t *)pte_offset +
((vaddr & 0x000ff000) >> 12);
pte_offset += 1024;
}
else /* using old Level 1 page table item */
{
p_pteentry = (rt_uint32_t *)(*pTT & 0xfffffc00) +
((vaddr & 0x000ff000) >> 12);
}
*p_pteentry = mdesc->page_attr | (((mdesc->paddr_start >> 12) + i) << 12);
vaddr += 0x1000;
}
}
static void build_pte_mem_desc(struct mem_desc *mdesc, rt_uint32_t size)
{
rt_uint32_t pte_offset = 0;
rt_uint32_t nsec = 0;
/* set page table */
for (; size > 0; size--)
{
if (mdesc->mapped_mode == PAGE_MAPPED)
{
nsec = (RT_ALIGN(mdesc->vaddr_end, 0x100000) - RT_ALIGN_DOWN(mdesc->vaddr_start, 0x100000)) >> 20;
mdesc->sect_attr |= (((rt_uint32_t)_pte_table)& 0xfffffc00) + pte_offset;
pte_offset += nsec << 10;
}
if (pte_offset >= RT_MMU_PTE_SIZE)
{
rt_kprintf("PTE table size too little\n");
RT_ASSERT(0);
}
mdesc++;
}
}
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size)
{
/* disable I/D cache */
mmu_disable_dcache();
mmu_disable_icache();
mmu_disable();
mmu_invalidate_tlb();
/* clear pgd and pte table */
rt_memset((void *)_pgd_table, 0, 16*1024);
rt_memset((void *)_pte_table, 0, RT_MMU_PTE_SIZE);
build_pte_mem_desc(mdesc, size);
/* set page table */
for (; size > 0; size--)
{
if (mdesc->mapped_mode == SECT_MAPPED)
{
mmu_create_pgd(mdesc);
}
else
{
mmu_create_pte(mdesc);
}
mdesc++;
}
/* set MMU table address */
mmu_setttbase((rt_uint32_t)_pgd_table);
/* enables MMU */
mmu_enable();
/* enable Instruction Cache */
mmu_enable_icache();
/* enable Data Cache */
mmu_enable_dcache();
mmu_invalidate_icache();
mmu_invalidate_dcache_all();
}

View File

@@ -0,0 +1,194 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef __MMU_H__
#define __MMU_H__
#include <rtthread.h>
#define CACHE_LINE_SIZE 32
/*
* Hardware page table definitions.
*
* + Level 1 descriptor (PGD)
* - common
*/
#define PGD_TYPE_MASK (3 << 0)
#define PGD_TYPE_FAULT (0 << 0)
#define PGD_TYPE_TABLE (1 << 0)
#define PGD_TYPE_SECT (2 << 0)
#define PGD_BIT4 (1 << 4)
#define PGD_DOMAIN(x) ((x) << 5)
#define PGD_PROTECTION (1 << 9) /* ARMv5 */
/*
* - section
*/
#define PGD_SECT_BUFFERABLE (1 << 2)
#define PGD_SECT_CACHEABLE (1 << 3)
#define PGD_SECT_XN (1 << 4) /* ARMv6 */
#define PGD_SECT_AP0 (1 << 10)
#define PGD_SECT_AP1 (1 << 11)
#define PGD_SECT_TEX(x) ((x) << 12) /* ARMv5 */
#define PGD_SECT_APX (1 << 15) /* ARMv6 */
#define PGD_SECT_S (1 << 16) /* ARMv6 */
#define PGD_SECT_nG (1 << 17) /* ARMv6 */
#define PGD_SECT_SUPER (1 << 18) /* ARMv6 */
#define PGD_SECT_UNCACHED (0)
#define PGD_SECT_BUFFERED (PGD_SECT_BUFFERABLE)
#define PGD_SECT_WT (PGD_SECT_CACHEABLE)
#define PGD_SECT_WB (PGD_SECT_CACHEABLE | PGD_SECT_BUFFERABLE)
#define PGD_SECT_MINICACHE (PGD_SECT_TEX(1) | PGD_SECT_CACHEABLE)
#define PGD_SECT_WBWA (PGD_SECT_TEX(1) | PGD_SECT_CACHEABLE | PGD_SECT_BUFFERABLE)
#define PGD_SECT_NONSHARED_DEV (PGD_SECT_TEX(2))
/*
* + Level 2 descriptor (PTE)
* - common
*/
#define PTE_TYPE_MASK (3 << 0)
#define PTE_TYPE_FAULT (0 << 0)
#define PTE_TYPE_LARGE (1 << 0)
#define PTE_TYPE_SMALL (2 << 0)
#define PTE_TYPE_EXT (3 << 0) /* ARMv5 */
#define PTE_BUFFERABLE (1 << 2)
#define PTE_CACHEABLE (1 << 3)
/*
* - extended small page/tiny page
*/
#define PTE_EXT_XN (1 << 0) /* ARMv6 */
#define PTE_EXT_AP_MASK (3 << 4)
#define PTE_EXT_AP0 (1 << 4)
#define PTE_EXT_AP1 (2 << 4)
#define PTE_EXT_AP_UNO_SRO (0 << 4)
#define PTE_EXT_AP_UNO_SRW (PTE_EXT_AP0)
#define PTE_EXT_AP_URO_SRW (PTE_EXT_AP1)
#define PTE_EXT_AP_URW_SRW (PTE_EXT_AP1|PTE_EXT_AP0)
#define PTE_EXT_TEX(x) ((x) << 6) /* ARMv5 */
#define PTE_EXT_APX (1 << 9) /* ARMv6 */
#define PTE_EXT_SHARED (1 << 10) /* ARMv6 */
#define PTE_EXT_NG (1 << 11) /* ARMv6 */
/*
* - small page
*/
#define PTE_SMALL_AP_MASK (0xff << 4)
#define PTE_SMALL_AP_UNO_SRO (0x00 << 4)
#define PTE_SMALL_AP_UNO_SRW (0x55 << 4)
#define PTE_SMALL_AP_URO_SRW (0xaa << 4)
#define PTE_SMALL_AP_URW_SRW (0xff << 4)
/*
* sector table properities
*/
#define SECT_CB (PGD_SECT_CACHEABLE|PGD_SECT_BUFFERABLE) //cache_on, write_back
#define SECT_CNB (PGD_SECT_CACHEABLE) //cache_on, write_through
#define SECT_NCB (PGD_SECT_BUFFERABLE) //cache_off,WR_BUF on
#define SECT_NCNB (0 << 2) //cache_off,WR_BUF off
#define SECT_AP_RW (PGD_SECT_AP0|PGD_SECT_AP1) //supervisor=RW, user=RW
#define SECT_AP_RO (PGD_SECT_AP0|PGD_SECT_AP1|PGD_SECT_APX) //supervisor=RO, user=RO
#define SECT_RWX_CB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT) /* Read/Write/executable, cache, write back */
#define SECT_RWX_CNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT) /* Read/Write/executable, cache, write through */
#define SECT_RWX_NCNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_TYPE_SECT) /* Read/Write/executable without cache and write buffer */
#define SECT_RWX_FAULT (SECT_AP_RW|PGD_DOMAIN(1)|PGD_TYPE_SECT) /* Read/Write without cache and write buffer */
#define SECT_RWNX_CB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write, cache, write back */
#define SECT_RWNX_CNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write, cache, write through */
#define SECT_RWNX_NCNB (SECT_AP_RW|PGD_DOMAIN(0)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write without cache and write buffer */
#define SECT_RWNX_FAULT (SECT_AP_RW|PGD_DOMAIN(1)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read/Write without cache and write buffer */
#define SECT_ROX_CB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT) /* Read Only/executable, cache, write back */
#define SECT_ROX_CNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT) /* Read Only/executable, cache, write through */
#define SECT_ROX_NCNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_TYPE_SECT) /* Read Only/executable without cache and write buffer */
#define SECT_ROX_FAULT (SECT_AP_RO|PGD_DOMAIN(1)|PGD_TYPE_SECT) /* Read Only without cache and write buffer */
#define SECT_RONX_CB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WB|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only, cache, write back */
#define SECT_RONX_CNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_SECT_WT|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only, cache, write through */
#define SECT_RONX_NCNB (SECT_AP_RO|PGD_DOMAIN(0)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only without cache and write buffer */
#define SECT_RONX_FAULT (SECT_AP_RO|PGD_DOMAIN(1)|PGD_TYPE_SECT|PGD_SECT_XN) /* Read Only without cache and write buffer */
#define SECT_TO_PAGE (PGD_DOMAIN(0)|PGD_TYPE_TABLE) /* Level 2 descriptor (PTE) entry properity */
/*
* page table properities
*/
#define PAGE_CB (PTE_BUFFERABLE|PTE_CACHEABLE) //cache_on, write_back
#define PAGE_CNB (PTE_CACHEABLE) //cache_on, write_through
#define PAGE_NCB (PTE_BUFFERABLE) //cache_off,WR_BUF on
#define PAGE_NCNB (0 << 2) //cache_off,WR_BUF off
#define PAGE_AP_RW (PTE_EXT_AP0|PTE_EXT_AP1) //supervisor=RW, user=RW
#define PAGE_AP_RO (PTE_EXT_AP0|PTE_EXT_AP1|PTE_EXT_APX) //supervisor=RO, user=RO
#define PAGE_RWX_CB (PAGE_AP_RW|PAGE_CB|PTE_TYPE_SMALL) /* Read/Write/executable, cache, write back */
#define PAGE_RWX_CNB (PAGE_AP_RW|PAGE_CNB|PTE_TYPE_SMALL) /* Read/Write/executable, cache, write through */
#define PAGE_RWX_NCNB (PAGE_AP_RW|PTE_TYPE_SMALL) /* Read/Write/executable without cache and write buffer */
#define PAGE_RWX_FAULT (PAGE_AP_RW|PTE_TYPE_SMALL) /* Read/Write without cache and write buffer */
#define PAGE_RWNX_CB (PAGE_AP_RW|PAGE_CB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write, cache, write back */
#define PAGE_RWNX_CNB (PAGE_AP_RW|PAGE_CNB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write, cache, write through */
#define PAGE_RWNX_NCNB (PAGE_AP_RW|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write without cache and write buffer */
#define PAGE_RWNX_FAULT (PAGE_AP_RW|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read/Write without cache and write buffer */
#define PAGE_ROX_CB (PAGE_AP_RO|PAGE_CB|PTE_TYPE_SMALL) /* Read Only/executable, cache, write back */
#define PAGE_ROX_CNB (PAGE_AP_RO|PAGE_CNB|PTE_TYPE_SMALL) /* Read Only/executable, cache, write through */
#define PAGE_ROX_NCNB (PAGE_AP_RO|PTE_TYPE_SMALL) /* Read Only/executable without cache and write buffer */
#define PAGE_ROX_FAULT (PAGE_AP_RO|PTE_TYPE_SMALL) /* Read Only without cache and write buffer */
#define PAGE_RONX_CB (PAGE_AP_RO|PAGE_CB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only, cache, write back */
#define PAGE_RONX_CNB (PAGE_AP_RO|PAGE_CNB|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only, cache, write through */
#define PAGE_RONX_NCNB (PAGE_AP_RO|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only without cache and write buffer */
#define PAGE_RONX_FAULT (PAGE_AP_RO|PTE_TYPE_SMALL|PTE_EXT_XN) /* Read Only without cache and write buffer */
#define DESC_SEC (0x2|(1<<4))
#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 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)
#define RW_CB (AP_RW|DOMAIN0|CB|DESC_SEC) /* Read/Write, cache, write back */
#define RW_CNB (AP_RW|DOMAIN0|CNB|DESC_SEC) /* Read/Write, cache, write through */
#define RW_NCNB (AP_RW|DOMAIN0|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
#define RW_FAULT (AP_RW|DOMAIN1|NCNB|DESC_SEC) /* Read/Write without cache and write buffer */
struct mem_desc {
rt_uint32_t vaddr_start;
rt_uint32_t vaddr_end;
rt_uint32_t paddr_start;
rt_uint32_t sect_attr; /* when page mapped */
rt_uint32_t page_attr; /* only sector mapped valid */
rt_uint32_t mapped_mode;
#define SECT_MAPPED 0
#define PAGE_MAPPED 1
};
void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size);
#endif

View File

@@ -0,0 +1,68 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-01-13 weety copy from mini2440
*/
#include <rtthread.h>
/*****************************/
/* CPU Mode */
/*****************************/
#define USERMODE 0x10
#define FIQMODE 0x11
#define IRQMODE 0x12
#define SVCMODE 0x13
#define ABORTMODE 0x17
#define UNDEFMODE 0x1b
#define MODEMASK 0x1f
#define NOINT 0xc0
/**
* 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;
stack_addr += sizeof(rt_uint32_t);
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
stk = (rt_uint32_t *)stack_addr;
*(--stk) = (rt_uint32_t)tentry; /* entry point */
*(--stk) = (rt_uint32_t)texit; /* lr */
*(--stk) = 0xdeadbeef; /* r12 */
*(--stk) = 0xdeadbeef; /* r11 */
*(--stk) = 0xdeadbeef; /* r10 */
*(--stk) = 0xdeadbeef; /* r9 */
*(--stk) = 0xdeadbeef; /* r8 */
*(--stk) = 0xdeadbeef; /* r7 */
*(--stk) = 0xdeadbeef; /* r6 */
*(--stk) = 0xdeadbeef; /* r5 */
*(--stk) = 0xdeadbeef; /* r4 */
*(--stk) = 0xdeadbeef; /* r3 */
*(--stk) = 0xdeadbeef; /* r2 */
*(--stk) = 0xdeadbeef; /* 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;
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2014-11-07 weety first version
*/
#include <rthw.h>
#include <rtthread.h>
#include "vfp.h"
#ifdef RT_USING_VFP
void vfp_init(void)
{
int ret = 0;
unsigned int value;
asm volatile ("mrc p15, 0, %0, c1, c0, 2"
:"=r"(value)
:);
value |= 0xf00000;/*enable CP10, CP11 user access*/
asm volatile("mcr p15, 0, %0, c1, c0, 2"
:
:"r"(value));
asm volatile("fmrx %0, fpexc"
:"=r"(value));
value |=(1<<30);
asm volatile("fmxr fpexc, %0"
:
:"r"(value));
}
#endif

View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2014-11-07 weety first version
*/
#ifndef __VFP_H__
#define __VFP_H__
/* FPSID register bits */
#define FPSID_IMPLEMENTER_BIT (24)
#define FPSID_IMPLEMENTER_MASK (0xff << FPSID_IMPLEMENTER_BIT)
#define FPSID_SW (1 << 23)
#define FPSID_FORMAT_BIT (21)
#define FPSID_FORMAT_MASK (0x3 << FPSID_FORMAT_BIT)
#define FPSID_NODOUBLE (1 << 20)
#define FPSID_ARCH_BIT (16)
#define FPSID_ARCH_MASK (0xF << FPSID_ARCH_BIT)
#define FPSID_PART_BIT (8)
#define FPSID_PART_MASK (0xFF << FPSID_PART_BIT)
#define FPSID_VARIANT_BIT (4)
#define FPSID_VARIANT_MASK (0xF << FPSID_VARIANT_BIT)
#define FPSID_REVISION_BIT (0)
#define FPSID_REVISION_MASK (0xF << FPSID_REVISION_BIT)
/* FPSCR register bits */
#define FPSCR_DN (1<<25) /* Default NaN mode enable bit */
#define FPSCR_FZ (1<<24) /* Flush-to-zero mode enable bit */
#define FPSCR_RN (0<<22) /* Round to nearest (RN) mode */
#define FPSCR_RP (1<<22) /* Round towards plus infinity (RP) mode */
#define FPSCR_RM (2<<22) /* Round towards minus infinity (RM) mode */
#define FPSCR_RZ (3<<22) /* Round towards zero (RZ) mode */
#define FPSCR_RMODE_BIT (22)
#define FPSCR_RMODE_MASK (3 << FPSCR_RMODE_BIT)
#define FPSCR_STRIDE_BIT (20)
#define FPSCR_STRIDE_MASK (3 << FPSCR_STRIDE_BIT)
#define FPSCR_LENGTH_BIT (16)
#define FPSCR_LENGTH_MASK (7 << FPSCR_LENGTH_BIT)
#define FPSCR_IDE (1<<15) /* Input Subnormal exception trap enable bit */
#define FPSCR_IXE (1<<12) /* Inexact exception trap enable bit */
#define FPSCR_UFE (1<<11) /* Underflow exception trap enable bit */
#define FPSCR_OFE (1<<10) /* Overflow exception trap enable bit */
#define FPSCR_DZE (1<<9) /* Division by Zero exception trap enable bit */
#define FPSCR_IOE (1<<8) /* Invalid Operation exception trap enable bit */
#define FPSCR_IDC (1<<7) /* Input Subnormal cumulative exception flag */
#define FPSCR_IXC (1<<4) /* Inexact cumulative exception flag */
#define FPSCR_UFC (1<<3) /* Underflow cumulative exception flag */
#define FPSCR_OFC (1<<2) /* Overflow cumulative exception flag */
#define FPSCR_DZC (1<<1) /* Division by Zero cumulative exception flag */
#define FPSCR_IOC (1<<0) /* Invalid Operation cumulative exception flag */
/* FPEXC register bits */
#define FPEXC_EX (1 << 31) /* When EX is set, the VFP coprocessor is in the exceptional state */
#define FPEXC_EN (1 << 30) /* VFP enable bit */
#define FPEXC_DEX (1 << 29) /* Defined synchronous instruction exceptional flag */
#define FPEXC_FP2V (1 << 28) /* FPINST2 instruction valid flag */
#define FPEXC_LENGTH_BIT (8)
#define FPEXC_LENGTH_MASK (7 << FPEXC_LENGTH_BIT)
#define FPEXC_INV (1 << 7) /* Input exception flag */
#define FPEXC_UFC (1 << 3) /* Potential underflow flag */
#define FPEXC_OFC (1 << 2) /* Potential overflow flag */
#define FPEXC_IOC (1 << 0) /* Potential invalid operation flag */
#define FPEXC_TRAP_MASK (FPEXC_INV|FPEXC_UFC|FPEXC_OFC|FPEXC_IOC)
/* MVFR0 register bits */
#define MVFR0_A_SIMD_BIT (0)
#define MVFR0_A_SIMD_MASK (0xf << MVFR0_A_SIMD_BIT)
/* thread switch micro */
#define THREAD_INIT 0
#define THREAD_EXIT 1
/*
* get VFP register
*/
#define vmrs(vfp) ({ \
rt_uint32_t var; \
asm("vmrs %0, "#vfp"" : "=r" (var) : : "cc"); \
var; \
})
#define vmsr(vfp, var) \
asm("vmsr "#vfp", %0" \
: : "r" (var) : "cc")
#endif

View File

@@ -0,0 +1,26 @@
# RT-Thread building script for component
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')
CPPPATH = [cwd]
if rtconfig.PLATFORM in ['armcc', 'armclang']:
src += Glob('*_rvds.S')
if rtconfig.PLATFORM in ['gcc']:
src += Glob('*_init.S')
src += Glob('*_gcc.S')
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
if not GetDepend('RT_USING_HW_ATOMIC'):
SrcRemove(src, 'atomic_arm.c')
group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@@ -0,0 +1,188 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-07-27 flybreak the first version
*/
#include <rtthread.h>
#if defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */
#include <intrinsics.h>
#include <iccarm_builtin.h>
#endif
/**
\brief LDR Exclusive (32 bit)
\details Executes a exclusive LDR instruction for 32 bit values.
\param [in] ptr Pointer to data
\return value of type uint32_t at (*ptr)
*/
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
#define __LDREXW (rt_atomic_t)__builtin_arm_ldrex
#elif defined(__ARMCC_VERSION) /* ARM Compiler V5 */
#if __ARMCC_VERSION < 5060020
#define __LDREXW(ptr) ((rt_atomic_t ) __ldrex(ptr))
#else
#define __LDREXW(ptr) _Pragma("push") _Pragma("diag_suppress 3731") ((rt_atomic_t ) __ldrex(ptr)) _Pragma("pop")
#endif
#elif defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */
_Pragma("inline=forced") __intrinsic rt_atomic_t __LDREXW(volatile rt_atomic_t *ptr)
{
return __iar_builtin_LDREX((volatile unsigned int *)ptr);
}
#elif defined (__GNUC__) /* GNU GCC Compiler */
__attribute__((always_inline)) static inline rt_atomic_t __LDREXW(volatile rt_atomic_t *addr)
{
rt_atomic_t result;
__asm volatile ("ldrex %0, %1" : "=r" (result) : "Q" (*addr) );
return result;
}
#endif
/**
\brief STR Exclusive (32 bit)
\details Executes a exclusive STR instruction for 32 bit values.
\param [in] value Value to store
\param [in] ptr Pointer to location
\return 0 Function succeeded
\return 1 Function failed
*/
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
#define __STREXW (rt_atomic_t)__builtin_arm_strex
#elif defined(__ARMCC_VERSION) /* ARM Compiler V5 */
#if __ARMCC_VERSION < 5060020
#define __STREXW(value, ptr) __strex(value, ptr)
#else
#define __STREXW(value, ptr) _Pragma("push") _Pragma("diag_suppress 3731") __strex(value, ptr) _Pragma("pop")
#endif
#elif defined (__IAR_SYSTEMS_ICC__) /* for IAR Compiler */
_Pragma("inline=forced") __intrinsic rt_atomic_t __STREXW(rt_atomic_t value, volatile rt_atomic_t *ptr)
{
return __STREX(value, (unsigned int *)ptr);
}
#elif defined (__GNUC__) /* GNU GCC Compiler */
__attribute__((always_inline)) static inline rt_atomic_t __STREXW(volatile rt_atomic_t value, volatile rt_atomic_t *addr)
{
rt_atomic_t result;
__asm volatile ("strex %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) );
return result;
}
#endif
rt_atomic_t rt_hw_atomic_load(volatile rt_atomic_t *ptr)
{
rt_atomic_t oldval;
do
{
oldval = __LDREXW(ptr);
} while ((__STREXW(oldval, ptr)) != 0U);
return oldval;
}
void rt_hw_atomic_store(volatile rt_atomic_t *ptr, rt_atomic_t val)
{
do
{
__LDREXW(ptr);
} while ((__STREXW(val, ptr)) != 0U);
}
rt_atomic_t rt_hw_atomic_add(volatile rt_atomic_t *ptr, rt_atomic_t val)
{
rt_atomic_t oldval;
do
{
oldval = __LDREXW(ptr);
} while ((__STREXW(oldval + val, ptr)) != 0U);
return oldval;
}
rt_atomic_t rt_hw_atomic_sub(volatile rt_atomic_t *ptr, rt_atomic_t val)
{
rt_atomic_t oldval;
do
{
oldval = __LDREXW(ptr);
} while ((__STREXW(oldval - val, ptr)) != 0U);
return oldval;
}
rt_atomic_t rt_hw_atomic_and(volatile rt_atomic_t *ptr, rt_atomic_t val)
{
rt_atomic_t oldval;
do
{
oldval = __LDREXW(ptr);
} while ((__STREXW(oldval & val, ptr)) != 0U);
return oldval;
}
rt_atomic_t rt_hw_atomic_or(volatile rt_atomic_t *ptr, rt_atomic_t val)
{
rt_atomic_t oldval;
do
{
oldval = __LDREXW(ptr);
} while ((__STREXW(oldval | val, ptr)) != 0U);
return oldval;
}
rt_atomic_t rt_hw_atomic_xor(volatile rt_atomic_t *ptr, rt_atomic_t val)
{
rt_atomic_t oldval;
do
{
oldval = __LDREXW(ptr);
} while ((__STREXW(oldval ^ val, ptr)) != 0U);
return oldval;
}
rt_atomic_t rt_hw_atomic_exchange(volatile rt_atomic_t *ptr, rt_atomic_t val)
{
rt_atomic_t oldval;
do
{
oldval = __LDREXW(ptr);
} while ((__STREXW(val, ptr)) != 0U);
return oldval;
}
void rt_hw_atomic_flag_clear(volatile rt_atomic_t *ptr)
{
do
{
__LDREXW(ptr);
} while ((__STREXW(0, ptr)) != 0U);
}
rt_atomic_t rt_hw_atomic_flag_test_and_set(volatile rt_atomic_t *ptr)
{
rt_atomic_t oldval;
do
{
oldval = __LDREXW(ptr);
} while ((__STREXW(1, ptr)) != 0U);
return oldval;
}
rt_atomic_t rt_hw_atomic_compare_exchange_strong(volatile rt_atomic_t *ptr, rt_atomic_t *old, rt_atomic_t new)
{
rt_atomic_t result;
rt_atomic_t temp = *old;
do
{
result = __LDREXW(ptr);
if (result != temp)
{
*old = result;
__STREXW(result, ptr);
break;
}
} while ((__STREXW(new, ptr)) != 0U);
return (result == temp);
}

View File

@@ -0,0 +1,12 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
void __div0(void)
{
while (1) ;
}

View File

@@ -0,0 +1,401 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
/* $NetBSD: divsi3.S,v 1.5 2005/02/26 22:58:56 perry Exp $ */
/*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* stack is aligned as there's a possibility of branching to L_overflow
* which makes a C call
*/
.text
.align 0
.globl __umodsi3
.type __umodsi3 , function
__umodsi3:
stmfd sp!, {lr}
sub sp, sp, #4 /* align stack */
bl .L_udivide
add sp, sp, #4 /* unalign stack */
mov r0, r1
ldmfd sp!, {pc}
.text
.align 0
.globl __modsi3
.type __modsi3 , function
__modsi3:
stmfd sp!, {lr}
sub sp, sp, #4 /* align stack */
bl .L_divide
add sp, sp, #4 /* unalign stack */
mov r0, r1
ldmfd sp!, {pc}
.L_overflow:
/* XXX should cause a fatal error */
mvn r0, #0
mov pc, lr
.text
.align 0
.globl __udivsi3
.type __udivsi3 , function
__udivsi3:
.L_udivide: /* r0 = r0 / r1; r1 = r0 % r1 */
eor r0, r1, r0
eor r1, r0, r1
eor r0, r1, r0
/* r0 = r1 / r0; r1 = r1 % r0 */
cmp r0, #1
bcc .L_overflow
beq .L_divide_l0
mov ip, #0
movs r1, r1
bpl .L_divide_l1
orr ip, ip, #0x20000000 /* ip bit 0x20000000 = -ve r1 */
movs r1, r1, lsr #1
orrcs ip, ip, #0x10000000 /* ip bit 0x10000000 = bit 0 of r1 */
b .L_divide_l1
.L_divide_l0: /* r0 == 1 */
mov r0, r1
mov r1, #0
mov pc, lr
.text
.align 0
.globl __divsi3
.type __divsi3 , function
__divsi3:
.L_divide: /* r0 = r0 / r1; r1 = r0 % r1 */
eor r0, r1, r0
eor r1, r0, r1
eor r0, r1, r0
/* r0 = r1 / r0; r1 = r1 % r0 */
cmp r0, #1
bcc .L_overflow
beq .L_divide_l0
ands ip, r0, #0x80000000
rsbmi r0, r0, #0
ands r2, r1, #0x80000000
eor ip, ip, r2
rsbmi r1, r1, #0
orr ip, r2, ip, lsr #1 /* ip bit 0x40000000 = -ve division */
/* ip bit 0x80000000 = -ve remainder */
.L_divide_l1:
mov r2, #1
mov r3, #0
/*
* If the highest bit of the dividend is set, we have to be
* careful when shifting the divisor. Test this.
*/
movs r1,r1
bpl .L_old_code
/*
* At this point, the highest bit of r1 is known to be set.
* We abuse this below in the tst instructions.
*/
tst r1, r0 /*, lsl #0 */
bmi .L_divide_b1
tst r1, r0, lsl #1
bmi .L_divide_b2
tst r1, r0, lsl #2
bmi .L_divide_b3
tst r1, r0, lsl #3
bmi .L_divide_b4
tst r1, r0, lsl #4
bmi .L_divide_b5
tst r1, r0, lsl #5
bmi .L_divide_b6
tst r1, r0, lsl #6
bmi .L_divide_b7
tst r1, r0, lsl #7
bmi .L_divide_b8
tst r1, r0, lsl #8
bmi .L_divide_b9
tst r1, r0, lsl #9
bmi .L_divide_b10
tst r1, r0, lsl #10
bmi .L_divide_b11
tst r1, r0, lsl #11
bmi .L_divide_b12
tst r1, r0, lsl #12
bmi .L_divide_b13
tst r1, r0, lsl #13
bmi .L_divide_b14
tst r1, r0, lsl #14
bmi .L_divide_b15
tst r1, r0, lsl #15
bmi .L_divide_b16
tst r1, r0, lsl #16
bmi .L_divide_b17
tst r1, r0, lsl #17
bmi .L_divide_b18
tst r1, r0, lsl #18
bmi .L_divide_b19
tst r1, r0, lsl #19
bmi .L_divide_b20
tst r1, r0, lsl #20
bmi .L_divide_b21
tst r1, r0, lsl #21
bmi .L_divide_b22
tst r1, r0, lsl #22
bmi .L_divide_b23
tst r1, r0, lsl #23
bmi .L_divide_b24
tst r1, r0, lsl #24
bmi .L_divide_b25
tst r1, r0, lsl #25
bmi .L_divide_b26
tst r1, r0, lsl #26
bmi .L_divide_b27
tst r1, r0, lsl #27
bmi .L_divide_b28
tst r1, r0, lsl #28
bmi .L_divide_b29
tst r1, r0, lsl #29
bmi .L_divide_b30
tst r1, r0, lsl #30
bmi .L_divide_b31
/*
* instead of:
* tst r1, r0, lsl #31
* bmi .L_divide_b32
*/
b .L_divide_b32
.L_old_code:
cmp r1, r0
bcc .L_divide_b0
cmp r1, r0, lsl #1
bcc .L_divide_b1
cmp r1, r0, lsl #2
bcc .L_divide_b2
cmp r1, r0, lsl #3
bcc .L_divide_b3
cmp r1, r0, lsl #4
bcc .L_divide_b4
cmp r1, r0, lsl #5
bcc .L_divide_b5
cmp r1, r0, lsl #6
bcc .L_divide_b6
cmp r1, r0, lsl #7
bcc .L_divide_b7
cmp r1, r0, lsl #8
bcc .L_divide_b8
cmp r1, r0, lsl #9
bcc .L_divide_b9
cmp r1, r0, lsl #10
bcc .L_divide_b10
cmp r1, r0, lsl #11
bcc .L_divide_b11
cmp r1, r0, lsl #12
bcc .L_divide_b12
cmp r1, r0, lsl #13
bcc .L_divide_b13
cmp r1, r0, lsl #14
bcc .L_divide_b14
cmp r1, r0, lsl #15
bcc .L_divide_b15
cmp r1, r0, lsl #16
bcc .L_divide_b16
cmp r1, r0, lsl #17
bcc .L_divide_b17
cmp r1, r0, lsl #18
bcc .L_divide_b18
cmp r1, r0, lsl #19
bcc .L_divide_b19
cmp r1, r0, lsl #20
bcc .L_divide_b20
cmp r1, r0, lsl #21
bcc .L_divide_b21
cmp r1, r0, lsl #22
bcc .L_divide_b22
cmp r1, r0, lsl #23
bcc .L_divide_b23
cmp r1, r0, lsl #24
bcc .L_divide_b24
cmp r1, r0, lsl #25
bcc .L_divide_b25
cmp r1, r0, lsl #26
bcc .L_divide_b26
cmp r1, r0, lsl #27
bcc .L_divide_b27
cmp r1, r0, lsl #28
bcc .L_divide_b28
cmp r1, r0, lsl #29
bcc .L_divide_b29
cmp r1, r0, lsl #30
bcc .L_divide_b30
.L_divide_b32:
cmp r1, r0, lsl #31
subhs r1, r1,r0, lsl #31
addhs r3, r3,r2, lsl #31
.L_divide_b31:
cmp r1, r0, lsl #30
subhs r1, r1,r0, lsl #30
addhs r3, r3,r2, lsl #30
.L_divide_b30:
cmp r1, r0, lsl #29
subhs r1, r1,r0, lsl #29
addhs r3, r3,r2, lsl #29
.L_divide_b29:
cmp r1, r0, lsl #28
subhs r1, r1,r0, lsl #28
addhs r3, r3,r2, lsl #28
.L_divide_b28:
cmp r1, r0, lsl #27
subhs r1, r1,r0, lsl #27
addhs r3, r3,r2, lsl #27
.L_divide_b27:
cmp r1, r0, lsl #26
subhs r1, r1,r0, lsl #26
addhs r3, r3,r2, lsl #26
.L_divide_b26:
cmp r1, r0, lsl #25
subhs r1, r1,r0, lsl #25
addhs r3, r3,r2, lsl #25
.L_divide_b25:
cmp r1, r0, lsl #24
subhs r1, r1,r0, lsl #24
addhs r3, r3,r2, lsl #24
.L_divide_b24:
cmp r1, r0, lsl #23
subhs r1, r1,r0, lsl #23
addhs r3, r3,r2, lsl #23
.L_divide_b23:
cmp r1, r0, lsl #22
subhs r1, r1,r0, lsl #22
addhs r3, r3,r2, lsl #22
.L_divide_b22:
cmp r1, r0, lsl #21
subhs r1, r1,r0, lsl #21
addhs r3, r3,r2, lsl #21
.L_divide_b21:
cmp r1, r0, lsl #20
subhs r1, r1,r0, lsl #20
addhs r3, r3,r2, lsl #20
.L_divide_b20:
cmp r1, r0, lsl #19
subhs r1, r1,r0, lsl #19
addhs r3, r3,r2, lsl #19
.L_divide_b19:
cmp r1, r0, lsl #18
subhs r1, r1,r0, lsl #18
addhs r3, r3,r2, lsl #18
.L_divide_b18:
cmp r1, r0, lsl #17
subhs r1, r1,r0, lsl #17
addhs r3, r3,r2, lsl #17
.L_divide_b17:
cmp r1, r0, lsl #16
subhs r1, r1,r0, lsl #16
addhs r3, r3,r2, lsl #16
.L_divide_b16:
cmp r1, r0, lsl #15
subhs r1, r1,r0, lsl #15
addhs r3, r3,r2, lsl #15
.L_divide_b15:
cmp r1, r0, lsl #14
subhs r1, r1,r0, lsl #14
addhs r3, r3,r2, lsl #14
.L_divide_b14:
cmp r1, r0, lsl #13
subhs r1, r1,r0, lsl #13
addhs r3, r3,r2, lsl #13
.L_divide_b13:
cmp r1, r0, lsl #12
subhs r1, r1,r0, lsl #12
addhs r3, r3,r2, lsl #12
.L_divide_b12:
cmp r1, r0, lsl #11
subhs r1, r1,r0, lsl #11
addhs r3, r3,r2, lsl #11
.L_divide_b11:
cmp r1, r0, lsl #10
subhs r1, r1,r0, lsl #10
addhs r3, r3,r2, lsl #10
.L_divide_b10:
cmp r1, r0, lsl #9
subhs r1, r1,r0, lsl #9
addhs r3, r3,r2, lsl #9
.L_divide_b9:
cmp r1, r0, lsl #8
subhs r1, r1,r0, lsl #8
addhs r3, r3,r2, lsl #8
.L_divide_b8:
cmp r1, r0, lsl #7
subhs r1, r1,r0, lsl #7
addhs r3, r3,r2, lsl #7
.L_divide_b7:
cmp r1, r0, lsl #6
subhs r1, r1,r0, lsl #6
addhs r3, r3,r2, lsl #6
.L_divide_b6:
cmp r1, r0, lsl #5
subhs r1, r1,r0, lsl #5
addhs r3, r3,r2, lsl #5
.L_divide_b5:
cmp r1, r0, lsl #4
subhs r1, r1,r0, lsl #4
addhs r3, r3,r2, lsl #4
.L_divide_b4:
cmp r1, r0, lsl #3
subhs r1, r1,r0, lsl #3
addhs r3, r3,r2, lsl #3
.L_divide_b3:
cmp r1, r0, lsl #2
subhs r1, r1,r0, lsl #2
addhs r3, r3,r2, lsl #2
.L_divide_b2:
cmp r1, r0, lsl #1
subhs r1, r1,r0, lsl #1
addhs r3, r3,r2, lsl #1
.L_divide_b1:
cmp r1, r0
subhs r1, r1, r0
addhs r3, r3, r2
.L_divide_b0:
tst ip, #0x20000000
bne .L_udivide_l1
mov r0, r3
cmp ip, #0
rsbmi r1, r1, #0
movs ip, ip, lsl #1
bicmi r0, r0, #0x80000000 /* Fix incase we divided 0x80000000 */
rsbmi r0, r0, #0
mov pc, lr
.L_udivide_l1:
tst ip, #0x10000000
mov r1, r1, lsl #1
orrne r1, r1, #1
mov r3, r3, lsl #1
cmp r1, r0
subhs r1, r1, r0
addhs r3, r3, r2
mov r0, r3
mov pc, lr

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2008-07-29 Bernard first version from QiuYi implementation
*/
#include <rtthread.h>
void rt_hw_show_memory(rt_uint32_t addr, rt_size_t size)
{
unsigned int i = 0, j = 0;
RT_ASSERT(addr);
addr = addr & ~0xF;
size = 4 * ((size + 3) / 4);
while (i < size)
{
rt_kprintf("0x%08x: ", addr);
for (j = 0; j < 4; j++)
{
rt_kprintf("0x%08x ", *(rt_uint32_t *)addr);
addr += 4;
i++;
}
rt_kprintf("\n");
}
return;
}

View File

@@ -0,0 +1,44 @@
# RT-Thread building script for component
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
src = Split('''
cache.c
cpuport.c
gtimer.c
mmu.c
pmu.c
stack.c
backtrace.c
''')
CPPPATH = [cwd]
if GetDepend('RT_USING_GIC_V2'):
src += ['interrupt.c']
src += ['gic.c']
src += ['trap.c']
if GetDepend('RT_USING_GIC_V3'):
src += ['interrupt.c']
src += ['gicv3.c']
src += ['trap.c']
if rtconfig.PLATFORM in ['armcc', 'armclang']:
src += Glob('*_rvds.S')
if rtconfig.PLATFORM in ['gcc']:
src += Glob('*_init.S')
src += Glob('*_gcc.S')
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2006-2023 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-03-12 WangXiaoyao the first version
*/
#ifndef __ASM_GENERIC_H__
#define __ASM_GENERIC_H__
#define START_POINT(funcname) \
.type funcname, %function; \
.global funcname; \
funcname: \
.cfi_sections .debug_frame, .eh_frame; \
.cfi_startproc; \
.cfi_undefined lr
#define START_POINT_END(name) \
.cfi_endproc; \
.size name, .-name;
#endif /* __ASM_GENERIC_H__ */

View File

@@ -0,0 +1,543 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-29 Jesven the first version
*/
#ifndef __CHECKER__
#if !defined (__ARM_EABI__)
#warning Your compiler does not have EABI support.
#warning ARM unwind is known to compile only with EABI compilers.
#warning Change compiler or disable ARM_UNWIND option.
#elif (__GNUC__ == 4 && __GNUC_MINOR__ <= 2) && !defined(__clang__)
#warning Your compiler is too buggy; it is known to not compile ARM unwind support.
#warning Change compiler or disable ARM_UNWIND option.
#endif
#endif /* __CHECKER__ */
#include <rtthread.h>
#include <rthw.h>
#include <backtrace.h>
#define DBG_TAG "BACKTRACE"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#ifdef RT_USING_SMART
#include <lwp.h>
#include <lwp_user_mm.h>
#include <lwp_arch.h>
#endif
rt_inline void arm_get_current_stackframe(struct pt_regs *regs, struct stackframe *frame)
{
frame->fp = frame_pointer(regs);
frame->sp = regs->ARM_sp;
frame->lr = regs->ARM_lr;
frame->pc = regs->ARM_pc;
}
struct unwind_ctrl_block {
unsigned long vrs[16]; /* virtual register set */
const unsigned long *insn; /* pointer to the current instructions word */
unsigned long sp_high; /* highest value of sp allowed */
/*
* 1 : check for stack overflow for each register pop.
* 0 : save overhead if there is plenty of stack remaining.
*/
int check_each_pop;
int entries; /* number of entries left to interpret */
int byte; /* current byte number in the instructions word */
};
enum regs
{
#ifdef CONFIG_THUMB2_KERNEL
FP = 7,
#else
FP = 11,
#endif
SP = 13,
LR = 14,
PC = 15
};
static int core_kernel_text(unsigned long addr)
{
return 1;
}
/* Convert a prel31 symbol to an absolute address */
#define prel31_to_addr(ptr) \
({ \
/* sign-extend to 32 bits */ \
long offset = (((long)*(ptr)) << 1) >> 1; \
(unsigned long)(ptr) + offset; \
})
/*
* Binary search in the unwind index. The entries are
* guaranteed to be sorted in ascending order by the linker.
*
* start = first entry
* origin = first entry with positive offset (or stop if there is no such entry)
* stop - 1 = last entry
*/
static const struct unwind_idx *search_index(unsigned long addr,
const struct unwind_idx *start,
const struct unwind_idx *origin,
const struct unwind_idx *stop)
{
unsigned long addr_prel31;
LOG_D("%s(%08lx, %x, %x, %x)",
__func__, addr, start, origin, stop);
/*
* only search in the section with the matching sign. This way the
* prel31 numbers can be compared as unsigned longs.
*/
if (addr < (unsigned long)start)
/* negative offsets: [start; origin) */
stop = origin;
else
/* positive offsets: [origin; stop) */
start = origin;
/* prel31 for address relavive to start */
addr_prel31 = (addr - (unsigned long)start) & 0x7fffffff;
while (start < stop - 1)
{
const struct unwind_idx *mid = start + ((stop - start) >> 1);
/*
* As addr_prel31 is relative to start an offset is needed to
* make it relative to mid.
*/
if (addr_prel31 - ((unsigned long)mid - (unsigned long)start) <
mid->addr_offset)
stop = mid;
else
{
/* keep addr_prel31 relative to start */
addr_prel31 -= ((unsigned long)mid -
(unsigned long)start);
start = mid;
}
}
if (start->addr_offset <= addr_prel31)
return start;
else
{
LOG_W("unwind: Unknown symbol address %08lx", addr);
return RT_NULL;
}
}
static const struct unwind_idx *unwind_find_origin(
const struct unwind_idx *start, const struct unwind_idx *stop)
{
LOG_D("%s(%x, %x)", __func__, start, stop);
while (start < stop)
{
const struct unwind_idx *mid = start + ((stop - start) >> 1);
if (mid->addr_offset >= 0x40000000)
/* negative offset */
start = mid + 1;
else
/* positive offset */
stop = mid;
}
LOG_D("%s -> %x", __func__, stop);
return stop;
}
static const struct unwind_idx *unwind_find_idx(unsigned long addr, const struct unwind_idx **origin_idx, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[])
{
const struct unwind_idx *idx = RT_NULL;
LOG_D("%s(%08lx)", __func__, addr);
if (core_kernel_text(addr))
{
if (!*origin_idx)
*origin_idx =
unwind_find_origin(exidx_start,
exidx_end);
/* main unwind table */
idx = search_index(addr, exidx_start,
*origin_idx,
exidx_end);
}
LOG_D("%s: idx = %x", __func__, idx);
return idx;
}
static unsigned long unwind_get_byte(struct unwind_ctrl_block *ctrl)
{
unsigned long ret;
if (ctrl->entries <= 0)
{
LOG_W("unwind: Corrupt unwind table");
return 0;
}
ret = (*ctrl->insn >> (ctrl->byte * 8)) & 0xff;
if (ctrl->byte == 0)
{
ctrl->insn++;
ctrl->entries--;
ctrl->byte = 3;
}
else
ctrl->byte--;
return ret;
}
/* Before poping a register check whether it is feasible or not */
static int unwind_pop_register(struct unwind_ctrl_block *ctrl,
unsigned long **vsp, unsigned int reg)
{
if (ctrl->check_each_pop)
if (*vsp >= (unsigned long *)ctrl->sp_high)
return -URC_FAILURE;
ctrl->vrs[reg] = *(*vsp)++;
return URC_OK;
}
/* Helper functions to execute the instructions */
static int unwind_exec_pop_subset_r4_to_r13(struct unwind_ctrl_block *ctrl,
unsigned long mask)
{
unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
int load_sp, reg = 4;
load_sp = mask & (1 << (13 - 4));
while (mask)
{
if (mask & 1)
if (unwind_pop_register(ctrl, &vsp, reg))
return -URC_FAILURE;
mask >>= 1;
reg++;
}
if (!load_sp)
ctrl->vrs[SP] = (unsigned long)vsp;
return URC_OK;
}
static int unwind_exec_pop_r4_to_rN(struct unwind_ctrl_block *ctrl,
unsigned long insn)
{
unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
int reg;
/* pop R4-R[4+bbb] */
for (reg = 4; reg <= 4 + (insn & 7); reg++)
if (unwind_pop_register(ctrl, &vsp, reg))
return -URC_FAILURE;
if (insn & 0x8)
if (unwind_pop_register(ctrl, &vsp, 14))
return -URC_FAILURE;
ctrl->vrs[SP] = (unsigned long)vsp;
return URC_OK;
}
static int unwind_exec_pop_subset_r0_to_r3(struct unwind_ctrl_block *ctrl,
unsigned long mask)
{
unsigned long *vsp = (unsigned long *)ctrl->vrs[SP];
int reg = 0;
/* pop R0-R3 according to mask */
while (mask)
{
if (mask & 1)
if (unwind_pop_register(ctrl, &vsp, reg))
return -URC_FAILURE;
mask >>= 1;
reg++;
}
ctrl->vrs[SP] = (unsigned long)vsp;
return URC_OK;
}
/*
* Execute the current unwind instruction.
*/
static int unwind_exec_insn(struct unwind_ctrl_block *ctrl)
{
unsigned long insn = unwind_get_byte(ctrl);
int ret = URC_OK;
LOG_D("%s: insn = %08lx", __func__, insn);
if ((insn & 0xc0) == 0x00)
ctrl->vrs[SP] += ((insn & 0x3f) << 2) + 4;
else if ((insn & 0xc0) == 0x40)
ctrl->vrs[SP] -= ((insn & 0x3f) << 2) + 4;
else if ((insn & 0xf0) == 0x80)
{
unsigned long mask;
insn = (insn << 8) | unwind_get_byte(ctrl);
mask = insn & 0x0fff;
if (mask == 0)
{
LOG_W("unwind: 'Refuse to unwind' instruction %04lx",
insn);
return -URC_FAILURE;
}
ret = unwind_exec_pop_subset_r4_to_r13(ctrl, mask);
if (ret)
goto error;
}
else if ((insn & 0xf0) == 0x90 &&
(insn & 0x0d) != 0x0d)
ctrl->vrs[SP] = ctrl->vrs[insn & 0x0f];
else if ((insn & 0xf0) == 0xa0)
{
ret = unwind_exec_pop_r4_to_rN(ctrl, insn);
if (ret)
goto error;
}
else if (insn == 0xb0)
{
if (ctrl->vrs[PC] == 0)
ctrl->vrs[PC] = ctrl->vrs[LR];
/* no further processing */
ctrl->entries = 0;
}
else if (insn == 0xb1)
{
unsigned long mask = unwind_get_byte(ctrl);
if (mask == 0 || mask & 0xf0)
{
LOG_W("unwind: Spare encoding %04lx",
(insn << 8) | mask);
return -URC_FAILURE;
}
ret = unwind_exec_pop_subset_r0_to_r3(ctrl, mask);
if (ret)
goto error;
}
else if (insn == 0xb2)
{
unsigned long uleb128 = unwind_get_byte(ctrl);
ctrl->vrs[SP] += 0x204 + (uleb128 << 2);
}
else
{
LOG_W("unwind: Unhandled instruction %02lx", insn);
return -URC_FAILURE;
}
LOG_D("%s: fp = %08lx sp = %08lx lr = %08lx pc = %08lx", __func__,
ctrl->vrs[FP], ctrl->vrs[SP], ctrl->vrs[LR], ctrl->vrs[PC]);
error:
return ret;
}
#ifdef RT_BACKTRACE_FUNCTION_NAME
static char *unwind_get_function_name(void *address)
{
uint32_t flag_word = *(uint32_t *)((char*)address - 4);
if ((flag_word & 0xff000000) == 0xff000000)
{
return (char *)((char*)address - 4 - (flag_word & 0x00ffffff));
}
return RT_NULL;
}
#endif
/*
* Unwind a single frame starting with *sp for the symbol at *pc. It
* updates the *pc and *sp with the new values.
*/
int unwind_frame(struct stackframe *frame, const struct unwind_idx **origin_idx, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[])
{
unsigned long low;
const struct unwind_idx *idx;
struct unwind_ctrl_block ctrl;
struct rt_thread *rt_c_thread;
/* store the highest address on the stack to avoid crossing it*/
low = frame->sp;
rt_c_thread = rt_thread_self();
ctrl.sp_high = (unsigned long)((char*)rt_c_thread->stack_addr + rt_c_thread->stack_size);
LOG_D("%s(pc = %08lx lr = %08lx sp = %08lx)", __func__,
frame->pc, frame->lr, frame->sp);
idx = unwind_find_idx(frame->pc, origin_idx, exidx_start, exidx_end);
if (!idx)
{
LOG_W("unwind: Index not found %08lx", frame->pc);
return -URC_FAILURE;
}
#ifdef RT_BACKTRACE_FUNCTION_NAME
{
char *fun_name;
fun_name = unwind_get_function_name((void *)prel31_to_addr(&idx->addr_offset));
if (fun_name)
{
rt_kprintf("0x%08x @ %s\n", frame->pc, fun_name);
}
}
#endif
ctrl.vrs[FP] = frame->fp;
ctrl.vrs[SP] = frame->sp;
ctrl.vrs[LR] = frame->lr;
ctrl.vrs[PC] = 0;
if (idx->insn == 1)
/* can't unwind */
return -URC_FAILURE;
else if ((idx->insn & 0x80000000) == 0)
/* prel31 to the unwind table */
ctrl.insn = (unsigned long *)prel31_to_addr(&idx->insn);
else if ((idx->insn & 0xff000000) == 0x80000000)
/* only personality routine 0 supported in the index */
ctrl.insn = &idx->insn;
else
{
LOG_W("unwind: Unsupported personality routine %08lx in the index at %x",
idx->insn, idx);
return -URC_FAILURE;
}
/* check the personality routine */
if ((*ctrl.insn & 0xff000000) == 0x80000000)
{
ctrl.byte = 2;
ctrl.entries = 1;
}
else if ((*ctrl.insn & 0xff000000) == 0x81000000)
{
ctrl.byte = 1;
ctrl.entries = 1 + ((*ctrl.insn & 0x00ff0000) >> 16);
}
else
{
LOG_W("unwind: Unsupported personality routine %08lx at %x",
*ctrl.insn, ctrl.insn);
return -URC_FAILURE;
}
ctrl.check_each_pop = 0;
while (ctrl.entries > 0)
{
int urc;
if ((ctrl.sp_high - ctrl.vrs[SP]) < sizeof(ctrl.vrs))
ctrl.check_each_pop = 1;
urc = unwind_exec_insn(&ctrl);
if (urc < 0)
return urc;
if (ctrl.vrs[SP] < low || ctrl.vrs[SP] >= ctrl.sp_high)
return -URC_FAILURE;
}
if (ctrl.vrs[PC] == 0)
ctrl.vrs[PC] = ctrl.vrs[LR];
/* check for infinite loop */
if (frame->pc == ctrl.vrs[PC])
return -URC_FAILURE;
frame->fp = ctrl.vrs[FP];
frame->sp = ctrl.vrs[SP];
frame->lr = ctrl.vrs[LR];
frame->pc = ctrl.vrs[PC];
return URC_OK;
}
void unwind_backtrace(struct pt_regs *regs, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[])
{
struct stackframe frame;
const struct unwind_idx *origin_idx = RT_NULL;
LOG_D("%s(regs = %x)", __func__, regs);
arm_get_current_stackframe(regs, &frame);
#ifndef RT_BACKTRACE_FUNCTION_NAME
rt_kprintf("please use: addr2line -e rtthread.elf -a -f %08x", frame.pc);
#endif
LOG_D("pc = %08x, sp = %08x", frame.pc, frame.sp);
while (1)
{
int urc;
urc = unwind_frame(&frame, &origin_idx, exidx_start, exidx_end);
if (urc < 0)
break;
//dump_backtrace_entry(where, frame.pc, frame.sp - 4);
#ifndef RT_BACKTRACE_FUNCTION_NAME
rt_kprintf(" %08x", frame.pc);
#endif
LOG_D("from: pc = %08x, frame = %08x", frame.pc, frame.sp - 4);
}
rt_kprintf("\n");
}
extern const struct unwind_idx __exidx_start[];
extern const struct unwind_idx __exidx_end[];
void rt_unwind(struct rt_hw_exp_stack *regs, unsigned int pc_adj)
{
struct pt_regs e_regs;
e_regs.ARM_fp = regs->fp;
e_regs.ARM_sp = regs->sp;
e_regs.ARM_lr = regs->lr;
e_regs.ARM_pc = regs->pc - pc_adj;
#ifdef RT_USING_SMART
if (!lwp_user_accessable((void *)e_regs.ARM_pc, sizeof (void *)))
{
e_regs.ARM_pc = regs->lr - sizeof(void *);
}
#endif
rt_kprintf("backtrace:\n");
unwind_backtrace(&e_regs, __exidx_start, __exidx_end);
}
rt_err_t rt_backtrace(void)
{
struct rt_hw_exp_stack regs;
asm volatile ("mov %0, fp":"=r"(regs.fp));
asm volatile ("mov %0, sp":"=r"(regs.sp));
asm volatile ("mov %0, lr":"=r"(regs.lr));
asm volatile ("mov %0, pc":"=r"(regs.pc));
rt_unwind(&regs, 8);
return RT_EOK;
}

View File

@@ -0,0 +1,83 @@
#ifndef __BACKTRACE_H
#define __BACKTRACE_H
#ifndef __ASSEMBLY__
#include <rtthread.h>
#include <cpuport.h>
/* Unwind reason code according the the ARM EABI documents */
enum unwind_reason_code
{
URC_OK = 0, /* operation completed successfully */
URC_CONTINUE_UNWIND = 8,
URC_FAILURE = 9 /* unspecified failure of some kind */
};
struct unwind_idx
{
unsigned long addr_offset;
unsigned long insn;
};
struct unwind_table
{
const struct unwind_idx *start;
const struct unwind_idx *origin;
const struct unwind_idx *stop;
unsigned long begin_addr;
unsigned long end_addr;
};
struct stackframe
{
/*
* FP member should hold R7 when CONFIG_THUMB2_KERNEL is enabled
* and R11 otherwise.
*/
unsigned long fp;
unsigned long sp;
unsigned long lr;
unsigned long pc;
};
struct pt_regs
{
unsigned long uregs[18];
};
#define ARM_cpsr uregs[16]
#define ARM_pc uregs[15]
#define ARM_lr uregs[14]
#define ARM_sp uregs[13]
#define ARM_ip uregs[12]
#define ARM_fp uregs[11]
#define ARM_r10 uregs[10]
#define ARM_r9 uregs[9]
#define ARM_r8 uregs[8]
#define ARM_r7 uregs[7]
#define ARM_r6 uregs[6]
#define ARM_r5 uregs[5]
#define ARM_r4 uregs[4]
#define ARM_r3 uregs[3]
#define ARM_r2 uregs[2]
#define ARM_r1 uregs[1]
#define ARM_r0 uregs[0]
#define ARM_ORIG_r0 uregs[17]
#define instruction_pointer(regs) (regs)->ARM_pc
#ifdef CONFIG_THUMB2_KERNEL
#define frame_pointer(regs) (regs)->ARM_r7
#else
#define frame_pointer(regs) (regs)->ARM_fp
#endif
int unwind_frame(struct stackframe *frame, const struct unwind_idx **origin_idx, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[]);
void unwind_backtrace(struct pt_regs *regs, const struct unwind_idx exidx_start[], const struct unwind_idx exidx_end[]);
void rt_unwind(struct rt_hw_exp_stack *regs, unsigned int pc_adj);
#endif /* !__ASSEMBLY__ */
#endif /* __BACKTRACE_H */

View File

@@ -0,0 +1,155 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-29 quanzhao the first version
*/
#include <rthw.h>
#include <rtdef.h>
rt_inline rt_uint32_t rt_cpu_icache_line_size(void)
{
rt_uint32_t ctr;
asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r"(ctr));
return 4 << (ctr & 0xF);
}
rt_inline rt_uint32_t rt_cpu_dcache_line_size(void)
{
rt_uint32_t ctr;
asm volatile ("mrc p15, 0, %0, c0, c0, 1" : "=r"(ctr));
return 4 << ((ctr >> 16) & 0xF);
}
void rt_hw_cpu_icache_invalidate(void *addr, int size)
{
rt_uint32_t line_size = rt_cpu_icache_line_size();
rt_uint32_t start_addr = (rt_uint32_t)addr;
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
asm volatile ("dmb":::"memory");
start_addr &= ~(line_size - 1);
end_addr &= ~(line_size - 1);
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c5, 1" :: "r"(start_addr)); /* icimvau */
start_addr += line_size;
}
asm volatile ("dsb\n\tisb":::"memory");
}
void rt_hw_cpu_dcache_invalidate(void *addr, int size)
{
rt_uint32_t line_size = rt_cpu_dcache_line_size();
rt_uint32_t start_addr = (rt_uint32_t)addr;
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
asm volatile ("dmb":::"memory");
start_addr &= ~(line_size - 1);
end_addr &= ~(line_size - 1);
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c6, 1" :: "r"(start_addr)); /* dcimvac */
start_addr += line_size;
}
asm volatile ("dsb":::"memory");
}
void rt_hw_cpu_dcache_inv_range(void *addr, int size)
{
rt_uint32_t line_size = rt_cpu_dcache_line_size();
rt_uint32_t start_addr = (rt_uint32_t)addr;
rt_uint32_t end_addr = (rt_uint32_t)addr + size;
asm volatile ("dmb":::"memory");
if ((start_addr & (line_size - 1)) != 0)
{
start_addr &= ~(line_size - 1);
asm volatile ("mcr p15, 0, %0, c7, c14, 1" :: "r"(start_addr));
start_addr += line_size;
asm volatile ("dsb":::"memory");
}
if ((end_addr & (line_size - 1)) != 0)
{
end_addr &= ~(line_size - 1);
asm volatile ("mcr p15, 0, %0, c7, c14, 1" :: "r"(end_addr));
asm volatile ("dsb":::"memory");
}
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c6, 1" :: "r"(start_addr)); /* dcimvac */
start_addr += line_size;
}
asm volatile ("dsb":::"memory");
}
void rt_hw_cpu_dcache_clean(void *addr, int size)
{
rt_uint32_t line_size = rt_cpu_dcache_line_size();
rt_uint32_t start_addr = (rt_uint32_t)addr;
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
asm volatile ("dmb":::"memory");
start_addr &= ~(line_size - 1);
end_addr &= ~(line_size - 1);
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c10, 1" :: "r"(start_addr)); /* dccmvac */
start_addr += line_size;
}
asm volatile ("dsb":::"memory");
}
void rt_hw_cpu_dcache_clean_and_invalidate(void *addr, int size)
{
rt_uint32_t line_size = rt_cpu_dcache_line_size();
rt_uint32_t start_addr = (rt_uint32_t)addr;
rt_uint32_t end_addr = (rt_uint32_t) addr + size + line_size - 1;
asm volatile ("dmb":::"memory");
start_addr &= ~(line_size - 1);
end_addr &= ~(line_size - 1);
while (start_addr < end_addr)
{
asm volatile ("mcr p15, 0, %0, c7, c10, 1" :: "r"(start_addr)); /* dccmvac */
asm volatile ("mcr p15, 0, %0, c7, c6, 1" :: "r"(start_addr)); /* dcimvac */
start_addr += line_size;
}
asm volatile ("dsb":::"memory");
}
void rt_hw_cpu_icache_ops(int ops, void *addr, int size)
{
if (ops == RT_HW_CACHE_INVALIDATE)
{
rt_hw_cpu_icache_invalidate(addr, size);
}
}
void rt_hw_cpu_dcache_ops(int ops, void *addr, int size)
{
if (ops == RT_HW_CACHE_FLUSH)
{
rt_hw_cpu_dcache_clean(addr, size);
}
else if (ops == RT_HW_CACHE_INVALIDATE)
{
rt_hw_cpu_dcache_invalidate(addr, size);
}
}
rt_base_t rt_hw_cpu_icache_status(void)
{
return 0;
}
rt_base_t rt_hw_cpu_dcache_status(void)
{
return 0;
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-29 quanzhao the first version
*/
#ifndef __CACHE_H__
#define __CACHE_H__
void rt_hw_cpu_icache_invalidate(void *addr, int size);
void rt_hw_cpu_dcache_clean_and_invalidate(void *addr, int size);
static inline void rt_hw_icache_invalidate_all(void)
{
__asm__ volatile("mcr p15, 0, %0, c7, c5, 0"::"r"(0ul));
}
#endif /* __CACHE_H__ */

View File

@@ -0,0 +1,268 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-05 Bernard the first version
*/
#include "rtconfig.h"
.section .text, "ax"
#ifdef RT_USING_SMP
#define rt_hw_interrupt_disable rt_hw_local_irq_disable
#define rt_hw_interrupt_enable rt_hw_local_irq_enable
#endif
/*
* 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, struct rt_thread *to_thread);
* r0 --> to (thread stack)
* r1 --> to_thread
*/
.globl rt_hw_context_switch_to
rt_hw_context_switch_to:
clrex
ldr sp, [r0] @ get new task stack pointer
#ifdef RT_USING_SMP
mov r0, r1
bl rt_cpus_lock_status_restore
#ifdef RT_USING_SMART
bl rt_thread_self
bl lwp_user_setting_restore
#endif
#else
#ifdef RT_USING_SMART
bl rt_thread_self
mov r4, r0
bl lwp_aspace_switch
mov r0, r4
bl lwp_user_setting_restore
#endif
#endif /*RT_USING_SMP*/
b rt_hw_context_switch_exit
.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, struct rt_thread *to_thread);
* r0 --> from (from_thread stack)
* r1 --> to (to_thread stack)
* r2 --> to_thread
*/
.globl rt_hw_context_switch
rt_hw_context_switch:
clrex
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
#ifdef RT_USING_SMART
stmfd sp, {r13, r14}^ @ push usr_sp usr_lr
sub sp, #8
#endif
#ifdef RT_USING_FPU
/* fpu context */
vmrs r6, fpexc
tst r6, #(1<<30)
beq 1f
vstmdb sp!, {d0-d15}
vstmdb sp!, {d16-d31}
vmrs r5, fpscr
stmfd sp!, {r5}
1:
stmfd sp!, {r6}
#endif
str sp, [r0] @ store sp in preempted tasks TCB
ldr sp, [r1] @ get new task stack pointer
#ifdef RT_USING_SMP
mov r0, r2
bl rt_cpus_lock_status_restore
#ifdef RT_USING_SMART
bl rt_thread_self
bl lwp_user_setting_restore
#endif
#else
#ifdef RT_USING_SMART
bl rt_thread_self
mov r4, r0
bl lwp_aspace_switch
mov r0, r4
bl lwp_user_setting_restore
#endif
#endif /*RT_USING_SMP*/
b rt_hw_context_switch_exit
/*
* void rt_hw_context_switch_interrupt(rt_uint32 from, rt_uint32 to);
*/
.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
.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:
clrex
#ifdef RT_USING_SMP
/* r0 :svc_mod context
* r1 :addr of from_thread's sp
* r2 :addr of to_thread's sp
* r3 :to_thread's tcb
*/
#ifdef RT_USING_SMART
push {r0 - r3, lr}
#ifdef RT_USING_SMART
bl rt_thread_self
bl lwp_user_setting_save
#endif
pop {r0 - r3, lr}
#endif
str r0, [r1]
ldr sp, [r2]
mov r0, r3
#ifdef RT_USING_SMART
mov r4, r0
#endif
bl rt_cpus_lock_status_restore
#ifdef RT_USING_SMART
mov r0, r4
bl lwp_user_setting_restore
#endif
b rt_hw_context_switch_exit
#else /*RT_USING_SMP*/
/* r0 :addr of from_thread's sp
* r1 :addr of to_thread's sp
* r2 :from_thread's tcb
* r3 :to_thread's tcb
*/
#ifdef RT_USING_SMART
/* now to_thread(r3) not used */
ldr ip, =rt_thread_switch_interrupt_flag
ldr r3, [ip]
cmp r3, #1
beq _reswitch
ldr r3, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
str r0, [r3]
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
str r3, [ip]
#ifdef RT_USING_SMART
push {r1, lr}
mov r0, r2
bl lwp_user_setting_save
pop {r1, lr}
#endif
_reswitch:
ldr ip, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
str r1, [ip]
bx lr
#else
/* now from_thread(r2) to_thread(r3) not used */
ldr ip, =rt_thread_switch_interrupt_flag
ldr r3, [ip]
cmp r3, #1
beq _reswitch
ldr r3, =rt_interrupt_from_thread @ set rt_interrupt_from_thread
str r0, [r3]
mov r3, #1 @ set rt_thread_switch_interrupt_flag to 1
str r3, [ip]
_reswitch:
ldr ip, =rt_interrupt_to_thread @ set rt_interrupt_to_thread
str r1, [ip]
bx lr
#endif
#endif /*RT_USING_SMP*/
.global rt_hw_context_switch_exit
rt_hw_context_switch_exit:
#ifdef RT_USING_SMP
#ifdef RT_USING_SIGNALS
mov r0, sp
cps #Mode_IRQ
bl rt_signal_check
cps #Mode_SVC
mov sp, r0
#endif
#endif
#ifdef RT_USING_FPU
/* fpu context */
ldmfd sp!, {r6}
vmsr fpexc, r6
tst r6, #(1<<30)
beq 1f
ldmfd sp!, {r5}
vmsr fpscr, r5
vldmia sp!, {d16-d31}
vldmia sp!, {d0-d15}
1:
#endif
#ifdef RT_USING_SMART
ldmfd sp, {r13, r14}^ /* usr_sp, usr_lr */
add sp, #8
#endif
ldmfd sp!, {r1}
msr spsr_cxsf, r1 /* original mode */
#ifdef RT_USING_SMART
and r1, #0x1f
cmp r1, #0x10
bne 1f
ldmfd sp!, {r0-r12,lr}
ldmfd sp!, {lr}
b arch_ret_to_user
1:
#endif
ldmfd sp!, {r0-r12,lr,pc}^ /* irq return */
#ifdef RT_USING_FPU
.global set_fpexc
set_fpexc:
vmsr fpexc, r0
bx lr
#endif

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-03-25 quanzhao the first version
*/
#ifndef __CP15_H__
#define __CP15_H__
#define __get_cp(cp, op1, Rt, CRn, CRm, op2) __asm__ volatile("MRC p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : "=r" (Rt) : : "memory" )
#define __set_cp(cp, op1, Rt, CRn, CRm, op2) __asm__ volatile("MCR p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : : "r" (Rt) : "memory" )
#define __get_cp64(cp, op1, Rt, CRm) __asm__ volatile("MRRC p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : "=r" (Rt) : : "memory" )
#define __set_cp64(cp, op1, Rt, CRm) __asm__ volatile("MCRR p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : : "r" (Rt) : "memory" )
int rt_hw_cpu_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_dcache_clean_flush(void);
void rt_cpu_icache_flush(void);
void rt_cpu_vector_set_base(unsigned int addr);
#endif

View File

@@ -0,0 +1,138 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* 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:
/* clear SCTRL.V to customize the vector address */
mrc p15, #0, r1, c1, c0, #0
bic r1, #(1 << 13)
mcr p15, #0, r1, c1, c0, #0
/* set up the vector address */
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 0x7fff
.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_cpu_icache_flush
rt_cpu_icache_flush:
mov r0, #0
mcr p15, 0, r0, c7, c5, 0 @ I+BTB cache invalidate
dsb
isb
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

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-09-15 Bernard first version
* 2018-11-22 Jesven add rt_hw_cpu_id()
*/
#include <rthw.h>
#include <rtthread.h>
#include <board.h>
rt_weak int rt_hw_cpu_id(void)
{
int cpu_id;
__asm__ volatile (
"mrc p15, 0, %0, c0, c0, 5"
:"=r"(cpu_id)
);
cpu_id &= 0xf;
return cpu_id;
}
#ifdef RT_USING_SMP
void rt_hw_spin_lock_init(rt_hw_spinlock_t *lock)
{
lock->slock = 0;
}
void rt_hw_spin_lock(rt_hw_spinlock_t *lock)
{
unsigned long tmp;
unsigned long newval;
rt_hw_spinlock_t lockval;
__asm__ __volatile__(
"pld [%0]"
::"r"(&lock->slock)
);
__asm__ __volatile__(
"1: ldrex %0, [%3]\n"
" add %1, %0, %4\n"
" strex %2, %1, [%3]\n"
" teq %2, #0\n"
" bne 1b"
: "=&r" (lockval), "=&r" (newval), "=&r" (tmp)
: "r" (&lock->slock), "I" (1 << 16)
: "cc");
while (lockval.tickets.next != lockval.tickets.owner) {
__asm__ __volatile__("wfe":::"memory");
lockval.tickets.owner = *(volatile unsigned short *)(&lock->tickets.owner);
}
__asm__ volatile ("dmb":::"memory");
}
void rt_hw_spin_unlock(rt_hw_spinlock_t *lock)
{
__asm__ volatile ("dmb":::"memory");
lock->tickets.owner++;
__asm__ volatile ("dsb ishst\nsev":::"memory");
}
#endif /*RT_USING_SMP*/
/**
* @addtogroup ARM CPU
*/
/*@{*/
/** shutdown CPU */
void rt_hw_cpu_shutdown(void)
{
rt_base_t level;
rt_kprintf("shutdown...\n");
level = rt_hw_interrupt_disable();
while (level)
{
RT_ASSERT(0);
}
}
#ifdef RT_USING_CPU_FFS
/**
* This function finds the first bit set (beginning with the least significant bit)
* in value and return the index of that bit.
*
* Bits are numbered starting at 1 (the least significant bit). A return value of
* zero from any of these functions means that the argument was zero.
*
* @return return the index of the first bit set. If value is 0, then this function
* shall return 0.
*/
int __rt_ffs(int value)
{
return __builtin_ffs(value);
}
#endif
rt_bool_t rt_hw_interrupt_is_disabled(void)
{
int rc;
__asm__ volatile("mrs %0, cpsr" : "=r" (rc));
return !!(rc & 0x80);
}
/*@}*/

View File

@@ -0,0 +1,102 @@
/*
* Copyright (c) 2006-2020, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#ifndef CPUPORT_H__
#define CPUPORT_H__
#include <rtcompiler.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)
#ifdef RT_USING_SMP
typedef union {
unsigned long slock;
struct __arch_tickets {
unsigned short owner;
unsigned short next;
} tickets;
} rt_hw_spinlock_t;
#endif
rt_inline void rt_hw_isb(void)
{
__asm volatile ("isb":::"memory");
}
rt_inline void rt_hw_dmb(void)
{
__asm volatile ("dmb":::"memory");
}
rt_inline void rt_hw_dsb(void)
{
__asm volatile ("dsb":::"memory");
}
void _thread_start(void);
#endif /*CPUPORT_H__*/

View File

@@ -0,0 +1,499 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
* 2014-04-03 Grissiom many enhancements
* 2018-11-22 Jesven add rt_hw_ipi_send()
* add rt_hw_ipi_handler_install()
*/
#include <rthw.h>
#include <rtthread.h>
#include "gic.h"
#include "cp15.h"
struct arm_gic
{
rt_uint32_t offset; /* the first interrupt index in the vector table */
rt_uint32_t dist_hw_base; /* the base address of the gic distributor */
rt_uint32_t cpu_hw_base; /* the base addrees of the gic cpu interface */
};
/* 'ARM_GIC_MAX_NR' is the number of cores */
static struct arm_gic _gic_table[ARM_GIC_MAX_NR];
/** Macro to access the Generic Interrupt Controller Interface (GICC)
*/
#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U)
#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U)
#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U)
#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU)
#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U)
#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U)
#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U)
#define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU)
/** Macro to access the Generic Interrupt Controller Distributor (GICD)
*/
#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U)
#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n)/32U) * 4U)
#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n)/32U) * 4U)
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n)/32U) * 4U)
#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n)/32U) * 4U)
#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n)/32U) * 4U)
#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n)/32U) * 4U)
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n)/32U) * 4U)
#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n)/4U) * 4U)
#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n)/4U) * 4U)
#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n)/16U) * 4U)
#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U)
#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n)/4U) * 4U)
#define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n)/4U) * 4U)
#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U)
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 = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
GIC_CPU_EOI(_gic_table[index].cpu_hw_base) = irq;
}
void arm_gic_mask(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
void arm_gic_umask(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
}
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
{
rt_uint32_t pend;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq >= 16U)
{
pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
}
else
{
/* INTID 0-15 Software Generated Interrupt */
pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
/* No CPU identification offered */
if (pend != 0U)
{
pend = 1U;
}
else
{
pend = 0U;
}
}
return (pend);
}
void arm_gic_set_pending_irq(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq >= 16U)
{
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1U << (irq % 32U);
}
else
{
/* INTID 0-15 Software Generated Interrupt */
/* Forward the interrupt to the CPU interface that requested it */
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000U);
}
}
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq)
{
rt_uint32_t mask;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq >= 16U)
{
mask = 1U << (irq % 32U);
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
else
{
mask = 1U << ((irq % 4U) * 8U);
GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask;
}
}
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config)
{
rt_uint32_t icfgr;
rt_uint32_t shift;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq);
shift = (irq % 16U) << 1U;
icfgr &= (~(3U << shift));
icfgr |= (config << (shift + 1));
GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
}
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
}
void arm_gic_clear_active(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
/* Set up the cpu mask for the specific interrupt */
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 >= 0U);
old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);
old_tgt &= ~(0x0FFUL << ((irq % 4U)*8U));
old_tgt |= cpumask << ((irq % 4U)*8U);
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
}
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
}
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority)
{
rt_uint32_t mask;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq);
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
}
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
}
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
/* set priority mask */
GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base) = priority & 0xFFUL;
}
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
return GIC_CPU_PRIMASK(_gic_table[index].cpu_hw_base);
}
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point)
{
GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base) = binary_point & 0x7U;
}
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index)
{
return GIC_CPU_BINPOINT(_gic_table[index].cpu_hw_base);
}
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
{
rt_uint32_t pending;
rt_uint32_t active;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
return ((active << 1U) | pending);
}
void arm_gic_send_sgi(rt_uint32_t index, int irq, rt_uint32_t target_list, rt_uint32_t filter_list)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = ((filter_list & 0x3U) << 24U) | ((target_list & 0xFFUL) << 16U) | (irq & 0x0FUL);
}
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
return GIC_CPU_HIGHPRI(_gic_table[index].cpu_hw_base);
}
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
}
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group)
{
rt_uint32_t igroupr;
rt_uint32_t shift;
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT(group <= 1U);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq);
shift = (irq % 32U);
igroupr &= (~(1U << shift));
igroupr |= ( (group & 0x1U) << shift);
GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
}
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
}
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 = 1U << 0U;
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 & 0x1fU) + 1U) * 32U;
/*
* The GIC only supports up to 1020 interrupt sources.
* Limit this to either the architected maximum, or the
* platform maximum.
*/
if (_gic_max_irq > 1020U)
_gic_max_irq = 1020U;
if (_gic_max_irq > ARM_GIC_NR_IRQS) /* the platform maximum interrupts */
_gic_max_irq = ARM_GIC_NR_IRQS;
cpumask |= cpumask << 8U;
cpumask |= cpumask << 16U;
cpumask |= cpumask << 24U;
GIC_DIST_CTRL(dist_base) = 0x0U;
/* Set all global interrupts to be level triggered, active low. */
for (i = 32U; i < _gic_max_irq; i += 16U)
GIC_DIST_CONFIG(dist_base, i) = 0x0U;
/* Set all global interrupts to this CPU only. */
for (i = 32U; i < _gic_max_irq; i += 4U)
GIC_DIST_TARGET(dist_base, i) = cpumask;
/* Set priority on all interrupts. */
for (i = 0U; i < _gic_max_irq; i += 4U)
GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0U;
/* Disable all interrupts. */
for (i = 0U; i < _gic_max_irq; i += 32U)
GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffffU;
#if 0
/* All interrupts defaults to IGROUP1(IRQ). */
for (i = 0; i < _gic_max_irq; i += 32)
GIC_DIST_IGROUP(dist_base, i) = 0xffffffff;
#endif
for (i = 0U; i < _gic_max_irq; i += 32U)
GIC_DIST_IGROUP(dist_base, i) = 0U;
/* Enable group0 and group1 interrupt forwarding. */
GIC_DIST_CTRL(dist_base) = 0x01U;
return 0;
}
int arm_gic_cpu_init(rt_uint32_t index, rt_uint32_t cpu_base)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
if (!_gic_table[index].cpu_hw_base)
{
_gic_table[index].cpu_hw_base = cpu_base;
}
cpu_base = _gic_table[index].cpu_hw_base;
GIC_CPU_PRIMASK(cpu_base) = 0xf0U;
GIC_CPU_BINPOINT(cpu_base) = 0x7U;
/* Enable CPU interrupt */
GIC_CPU_CTRL(cpu_base) = 0x01U;
return 0;
}
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) >> 4U) & 0xfUL,
_gic_table[index].dist_hw_base,
_gic_max_irq,
gic_type & (1U << 10U) ? "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 = 0U; i < _gic_max_irq / 32U; i++)
{
rt_kprintf("0x%08x, ",
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base,
i * 32U));
}
rt_kprintf("\n--- hw pending ---\n");
for (i = 0U; i < _gic_max_irq / 32U; i++)
{
rt_kprintf("0x%08x, ",
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base,
i * 32U));
}
rt_kprintf("\n--- hw active ---\n");
for (i = 0U; i < _gic_max_irq / 32U; i++)
{
rt_kprintf("0x%08x, ",
GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base,
i * 32U));
}
rt_kprintf("\n");
}
long gic_dump(void)
{
arm_gic_dump_type(0);
arm_gic_dump(0);
return 0;
}
MSH_CMD_EXPORT(gic_dump, show gic status);

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
*/
#ifndef __GIC_H__
#define __GIC_H__
#include <rthw.h>
#include <board.h>
int arm_gic_get_active_irq(rt_uint32_t index);
void arm_gic_ack(rt_uint32_t index, int irq);
void arm_gic_mask(rt_uint32_t index, int irq);
void arm_gic_umask(rt_uint32_t index, int irq);
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq);
void arm_gic_set_pending_irq(rt_uint32_t index, int irq);
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq);
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config);
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq);
void arm_gic_clear_active(rt_uint32_t index, int irq);
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask);
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq);
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority);
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq);
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority);
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index);
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point);
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index);
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq);
void arm_gic_send_sgi(rt_uint32_t index, int irq, rt_uint32_t target_list, rt_uint32_t filter_list);
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index);
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index);
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group);
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq);
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_dump_type(rt_uint32_t index);
void arm_gic_dump(rt_uint32_t index);
#endif

View File

@@ -0,0 +1,708 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
* 2014-04-03 Grissiom many enhancements
* 2018-11-22 Jesven add rt_hw_ipi_send()
* add rt_hw_ipi_handler_install()
*/
#include <rthw.h>
#include <rtthread.h>
#include "gicv3.h"
#include "cp15.h"
#ifndef RT_CPUS_NR
#define RT_CPUS_NR 1
#endif
struct arm_gic_v3
{
rt_uint32_t offset; /* the first interrupt index in the vector table */
rt_uint32_t redist_hw_base[RT_CPUS_NR]; /* the pointer of the gic redistributor */
rt_uint32_t dist_hw_base; /* the base address of the gic distributor */
rt_uint32_t cpu_hw_base[RT_CPUS_NR]; /* the base addrees of the gic cpu interface */
};
/* 'ARM_GIC_MAX_NR' is the number of cores */
static struct arm_gic_v3 _gic_table[ARM_GIC_MAX_NR];
static unsigned int _gic_max_irq;
/**
* @name: arm_gic_cpumask_to_affval
* @msg:
* @in param cpu_mask:
* @out param cluster_id: aff1 [0:7],aff2 [8:15],aff3 [16:23]
* @out param target_list: Target List. The set of PEs for which SGI interrupts will be generated. Each bit corresponds to the
* PE within a cluster with an Affinity 0 value equal to the bit number.
* @return {rt_uint32_t} 0 is finish , 1 is data valid
*/
rt_weak rt_uint32_t arm_gic_cpumask_to_affval(rt_uint32_t *cpu_mask, rt_uint32_t *cluster_id, rt_uint32_t *target_list)
{
return 0;
}
rt_weak rt_uint64_t get_main_cpu_affval(void)
{
return 0;
}
int arm_gic_get_active_irq(rt_uint32_t index)
{
int irq;
RT_ASSERT(index < ARM_GIC_MAX_NR);
__get_gicv3_reg(ICC_IAR1, irq);
irq = (irq & 0x1FFFFFF) + _gic_table[index].offset;
return irq;
}
void arm_gic_ack(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT(irq >= 0U);
__asm__ volatile("dsb 0xF" ::
: "memory");
__set_gicv3_reg(ICC_EOIR1, irq);
}
void arm_gic_mask(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq < 32U)
{
rt_int32_t cpu_id = rt_hw_cpu_id();
RT_ASSERT((cpu_id) < RT_CPUS_NR);
GIC_RDISTSGI_ICENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask;
}
else
{
GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
}
void arm_gic_umask(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq < 32U)
{
rt_int32_t cpu_id = rt_hw_cpu_id();
RT_ASSERT((cpu_id) < RT_CPUS_NR);
GIC_RDISTSGI_ISENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask;
}
else
{
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
}
}
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq)
{
rt_uint32_t pend;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq >= 16U)
{
pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
}
else
{
/* INTID 0-15 Software Generated Interrupt */
pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
/* No CPU identification offered */
if (pend != 0U)
{
pend = 1U;
}
else
{
pend = 0U;
}
}
return (pend);
}
void arm_gic_set_pending_irq(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq >= 16U)
{
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1U << (irq % 32U);
}
else
{
/* INTID 0-15 Software Generated Interrupt */
/* Forward the interrupt to the CPU interface that requested it */
GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000U);
}
}
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq)
{
rt_uint32_t mask;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq >= 16U)
{
mask = 1U << (irq % 32U);
GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
else
{
mask = 1U << ((irq % 4U) * 8U);
GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask;
}
}
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config)
{
rt_uint32_t icfgr;
rt_uint32_t shift;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq);
shift = (irq % 16U) << 1U;
icfgr &= (~(3U << shift));
icfgr |= (config << (shift + 1));
GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
}
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
}
void arm_gic_clear_active(rt_uint32_t index, int irq)
{
rt_uint32_t mask = 1U << (irq % 32U);
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}
/* Set up the cpu mask for the specific interrupt */
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 >= 0U);
old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);
old_tgt &= ~(0x0FFUL << ((irq % 4U) * 8U));
old_tgt |= cpumask << ((irq % 4U) * 8U);
GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
}
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
}
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority)
{
rt_uint32_t mask;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq < 32U)
{
rt_int32_t cpu_id = rt_hw_cpu_id();
RT_ASSERT((cpu_id) < RT_CPUS_NR);
mask = GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq);
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) = mask;
}
else
{
mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq);
mask &= ~(0xFFUL << ((irq % 4U) * 8U));
mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
}
}
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
if (irq < 32U)
{
rt_int32_t cpu_id = rt_hw_cpu_id();
RT_ASSERT((cpu_id) < RT_CPUS_NR);
return (GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
}
else
{
return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
}
}
void arm_gic_set_system_register_enable_mask(rt_uint32_t index, rt_uint32_t value)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
value &= 0xFFUL;
/* set priority mask */
__set_gicv3_reg(ICC_SRE, value);
__asm__ volatile ("isb 0xF"::
:"memory");
}
rt_uint32_t arm_gic_get_system_register_enable_mask(rt_uint32_t index)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
rt_uint32_t value;
__get_gicv3_reg(ICC_SRE, value);
return value;
}
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
priority &= 0xFFUL;
/* set priority mask */
__set_gicv3_reg(ICC_PMR, priority);
}
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
rt_uint32_t priority;
__get_gicv3_reg(ICC_PMR, priority);
return priority;
}
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point)
{
index = index;
binary_point &= 0x7U;
__set_gicv3_reg(ICC_BPR1, binary_point);
}
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index)
{
rt_uint32_t binary_point;
index = index;
__get_gicv3_reg(ICC_BPR1, binary_point);
return binary_point;
}
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq)
{
rt_uint32_t pending;
rt_uint32_t active;
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
return ((active << 1U) | pending);
}
void arm_gic_send_affinity_sgi(rt_uint32_t index, int irq, rt_uint32_t cpu_mask, rt_uint32_t routing_mode)
{
rt_uint64_t sgi_val;
if (routing_mode)
{
sgi_val = (1ULL << 40) | ((irq & 0x0FULL) << 24); //Interrupts routed to all PEs in the system, excluding "self".
/* Write the ICC_SGI1R registers */
__asm__ volatile("dsb 0xF" ::
: "memory");
__set_cp64(15, 0, sgi_val, 12);
__asm__ volatile("isb 0xF" ::
: "memory");
}
else
{
rt_uint32_t cluster_id, target_list;
while (arm_gic_cpumask_to_affval(&cpu_mask, &cluster_id, &target_list))
{
sgi_val = ((irq & 0x0FULL) << 24 |
target_list |
((cluster_id >> 8) & 0xFFULL) << GIC_RSGI_AFF1_OFFSET |
((cluster_id >> 16) & 0xFFULL) << GIC_RSGI_AFF2_OFFSET |
((cluster_id >> 24) & 0xFFull) << GIC_RSGI_AFF3_OFFSET);
__asm__ volatile("dsb 0xF" ::
: "memory");
__set_cp64(15, 0, sgi_val, 12);
__asm__ volatile("isb 0xF" ::
: "memory");
}
}
}
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index)
{
rt_uint32_t irq;
RT_ASSERT(index < ARM_GIC_MAX_NR);
index = index;
__get_gicv3_reg(ICC_HPPIR1, irq);
return irq;
}
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
}
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group)
{
rt_uint32_t igroupr;
rt_uint32_t shift;
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT(group <= 1U);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq);
shift = (irq % 32U);
igroupr &= (~(1U << shift));
igroupr |= ((group & 0x1U) << shift);
GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
}
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
irq = irq - _gic_table[index].offset;
RT_ASSERT(irq >= 0U);
return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
}
static int arm_gicv3_wait_rwp(rt_uint32_t index, rt_uint32_t irq)
{
rt_uint32_t rwp_bit;
rt_uint32_t base;
RT_ASSERT(index < ARM_GIC_MAX_NR);
if (irq < 32u)
{
rt_int32_t cpu_id = rt_hw_cpu_id();
RT_ASSERT((cpu_id) < RT_CPUS_NR);
base = _gic_table[index].redist_hw_base[cpu_id];
rwp_bit = GICR_CTLR_RWP;
}
else
{
base = _gic_table[index].dist_hw_base;
rwp_bit = GICD_CTLR_RWP;
}
while (__REG32(base) & rwp_bit)
{
;
}
return 0;
}
int arm_gic_dist_init(rt_uint32_t index, rt_uint32_t dist_base, int irq_start)
{
rt_uint64_t cpu0_affval;
unsigned int gic_type, i;
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 & 0x1fU) + 1U) * 32U;
/*
* The GIC only supports up to 1020 interrupt sources.
* Limit this to either the architected maximum, or the
* platform maximum.
*/
if (_gic_max_irq > 1020U)
_gic_max_irq = 1020U;
if (_gic_max_irq > ARM_GIC_NR_IRQS) /* the platform maximum interrupts */
_gic_max_irq = ARM_GIC_NR_IRQS;
GIC_DIST_CTRL(dist_base) = 0x0U;
/* Wait for register write pending */
arm_gicv3_wait_rwp(0, 32);
/* Set all global interrupts to be level triggered, active low. */
for (i = 32U; i < _gic_max_irq; i += 16U)
GIC_DIST_CONFIG(dist_base, i) = 0x0U;
arm_gicv3_wait_rwp(0, 32);
cpu0_affval = get_main_cpu_affval();
/* Set all global interrupts to this CPU only. */
for (i = 32U; i < _gic_max_irq; i++)
{
GIC_DIST_IROUTER_LOW(dist_base, i) = cpu0_affval;
GIC_DIST_IROUTER_HIGH(dist_base, i) = cpu0_affval >> 32;
}
arm_gicv3_wait_rwp(0, 32);
/* Set priority on spi interrupts. */
for (i = 32U; i < _gic_max_irq; i += 4U)
GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0U;
arm_gicv3_wait_rwp(0, 32);
/* Disable all interrupts. */
for (i = 0U; i < _gic_max_irq; i += 32U)
{
GIC_DIST_PENDING_CLEAR(dist_base, i) = 0xffffffffU;
GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffffU;
}
arm_gicv3_wait_rwp(0, 32);
/* All interrupts defaults to IGROUP1(IRQ). */
for (i = 0U; i < _gic_max_irq; i += 32U)
GIC_DIST_IGROUP(dist_base, i) = 0xffffffffU;
arm_gicv3_wait_rwp(0, 32);
/*
The Distributor control register (GICD_CTLR) must be configured to enable the interrupt groups and to set the routing mode.
Enable Affinity routing (ARE bits) The ARE bits in GICD_CTLR control whether affinity routing is enabled.
If affinity routing is not enabled, GICv3 can be configured for legacy operation.
Whether affinity routing is enabled or not can be controlled separately for Secure and Non-secure state.
Enables GICD_CTLR contains separate enable bits for Group 0, Secure Group 1 and Non-secure Group 1:
GICD_CTLR.EnableGrp1S enables distribution of Secure Group 1 interrupts.
GICD_CTLR.EnableGrp1NS enables distribution of Non-secure Group 1 interrupts.
GICD_CTLR.EnableGrp0 enables distribution of Group 0 interrupts.
*/
GIC_DIST_CTRL(dist_base) = GICD_CTLR_ARE_NS | GICD_CTLR_ENGRP1NS;
return 0;
}
int arm_gic_redist_address_set(rt_uint32_t index, rt_uint32_t redist_addr, rt_uint32_t cpu_id)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT((cpu_id) < RT_CPUS_NR);
_gic_table[index].redist_hw_base[cpu_id] = redist_addr;
return 0;
}
int arm_gic_cpu_interface_address_set(rt_uint32_t index, rt_uint32_t interface_addr, rt_uint32_t cpu_id)
{
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT((cpu_id) < RT_CPUS_NR);
_gic_table[index].cpu_hw_base[cpu_id] = interface_addr;
return 0;
}
int arm_gic_redist_init(rt_uint32_t index)
{
unsigned int i;
rt_uint32_t base;
rt_int32_t cpu_id = rt_hw_cpu_id();
RT_ASSERT(index < ARM_GIC_MAX_NR);
RT_ASSERT((cpu_id) < RT_CPUS_NR);
base = _gic_table[index].redist_hw_base[cpu_id];
/* redistributor enable */
GIC_RDIST_WAKER(base) &= ~(1U << 1);
while (GIC_RDIST_WAKER(base) & (1 << 2))
{
;
}
/* Disable all sgi and ppi interrupt */
GIC_RDISTSGI_ICENABLER0(base) = 0xFFFFFFFF;
arm_gicv3_wait_rwp(0, 0);
/* Clear all inetrrupt pending */
GIC_RDISTSGI_ICPENDR0(base) = 0xFFFFFFFF;
/* the corresponding interrupt is Group 1 or Non-secure Group 1. */
GIC_RDISTSGI_IGROUPR0(base, 0) = 0xFFFFFFFF;
GIC_RDISTSGI_IGRPMODR0(base, 0) = 0xFFFFFFFF;
/* Configure default priorities for SGI 0:15 and PPI 16:31. */
for (i = 0; i < 32; i += 4)
{
GIC_RDISTSGI_IPRIORITYR(base, i) = 0xa0a0a0a0U;
}
/* Trigger level for PPI interrupts*/
GIC_RDISTSGI_ICFGR1(base) = 0x0U; // PPI is level-sensitive.
return 0;
}
int arm_gic_cpu_init(rt_uint32_t index)
{
rt_uint32_t value;
RT_ASSERT(index < ARM_GIC_MAX_NR);
value = arm_gic_get_system_register_enable_mask(index);
value |= (1U << 0);
arm_gic_set_system_register_enable_mask(index, value);
__set_gicv3_reg(ICC_CTLR, 0);
arm_gic_set_interface_prior_mask(index, 0xFFU);
/* Enable group1 interrupt */
value = 0x1U;
__set_gicv3_reg(ICC_IGRPEN1, value);
arm_gic_set_binary_point(0, 0);
/* ICC_BPR0_EL1 determines the preemption group for both
Group 0 and Group 1 interrupts.
*/
value = 0x1U;
__set_gicv3_reg(ICC_CTLR, value);
return 0;
}
#ifdef RT_USING_SMP
void arm_gic_secondary_cpu_init(void)
{
arm_gic_redist_init(0);
arm_gic_cpu_init(0);
}
#endif
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) >> 4U) & 0xfUL,
_gic_table[index].dist_hw_base,
_gic_max_irq,
gic_type & (1U << 10U) ? "has" : "no",
gic_type);
}
void arm_gic_dump(rt_uint32_t index)
{
unsigned int i, k;
k = arm_gic_get_high_pending_irq(0);
rt_kprintf("--- high pending priority: %d(%08x)\n", k, k);
rt_kprintf("--- hw mask ---\n");
for (i = 0U; i < _gic_max_irq / 32U; i++)
{
rt_kprintf("0x%08x, ",
GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base,
i * 32U));
}
rt_kprintf("\n--- hw pending ---\n");
for (i = 0U; i < _gic_max_irq / 32U; i++)
{
rt_kprintf("0x%08x, ",
GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base,
i * 32U));
}
rt_kprintf("\n--- hw active ---\n");
for (i = 0U; i < _gic_max_irq / 32U; i++)
{
rt_kprintf("0x%08x, ",
GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base,
i * 32U));
}
rt_kprintf("\n");
}
long gic_dump(void)
{
arm_gic_dump_type(0);
arm_gic_dump(0);
return 0;
}
MSH_CMD_EXPORT(gic_dump, show gic status);

View File

@@ -0,0 +1,194 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
*/
#ifndef __GIC_V3_H__
#define __GIC_V3_H__
#include <rthw.h>
#include <board.h>
#define __get_gicv3_reg(CR, Rt) __asm__ volatile("MRC " CR \
: "=r"(Rt) \
: \
: "memory")
#define __set_gicv3_reg(CR, Rt) __asm__ volatile("MCR " CR \
: \
: "r"(Rt) \
: "memory")
/* AArch32 System register interface to GICv3 */
#define ICC_IAR0 "p15, 0, %0, c12, c8, 0"
#define ICC_IAR1 "p15, 0, %0, c12, c12, 0"
#define ICC_EOIR0 "p15, 0, %0, c12, c8, 1"
#define ICC_EOIR1 "p15, 0, %0, c12, c12, 1"
#define ICC_HPPIR0 "p15, 0, %0, c12, c8, 2"
#define ICC_HPPIR1 "p15, 0, %0, c12, c12, 2"
#define ICC_BPR0 "p15, 0, %0, c12, c8, 3"
#define ICC_BPR1 "p15, 0, %0, c12, c12, 3"
#define ICC_DIR "p15, 0, %0, c12, c11, 1"
#define ICC_PMR "p15, 0, %0, c4, c6, 0"
#define ICC_RPR "p15, 0, %0, c12, c11, 3"
#define ICC_CTLR "p15, 0, %0, c12, c12, 4"
#define ICC_MCTLR "p15, 6, %0, c12, c12, 4"
#define ICC_SRE "p15, 0, %0, c12, c12, 5"
#define ICC_HSRE "p15, 4, %0, c12, c9, 5"
#define ICC_MSRE "p15, 6, %0, c12, c12, 5"
#define ICC_IGRPEN0 "p15, 0, %0, c12, c12, 6"
#define ICC_IGRPEN1 "p15, 0, %0, c12, c12, 7"
#define ICC_MGRPEN1 "p15, 6, %0, c12, c12, 7"
#define __REG32(x) (*((volatile unsigned int*)((rt_uint32_t)x)))
#define ROUTED_TO_ALL (1)
#define ROUTED_TO_SPEC (0)
/** Macro to access the Distributor Control Register (GICD_CTLR)
*/
#define GICD_CTLR_RWP (1<<31)
#define GICD_CTLR_E1NWF (1<<7)
#define GICD_CTLR_DS (1<<6)
#define GICD_CTLR_ARE_NS (1<<5)
#define GICD_CTLR_ARE_S (1<<4)
#define GICD_CTLR_ENGRP1S (1<<2)
#define GICD_CTLR_ENGRP1NS (1<<1)
#define GICD_CTLR_ENGRP0 (1<<0)
/** Macro to access the Redistributor Control Register (GICR_CTLR)
*/
#define GICR_CTLR_UWP (1<<31)
#define GICR_CTLR_DPG1S (1<<26)
#define GICR_CTLR_DPG1NS (1<<25)
#define GICR_CTLR_DPG0 (1<<24)
#define GICR_CTLR_RWP (1<<3)
#define GICR_CTLR_IR (1<<2)
#define GICR_CTLR_CES (1<<1)
#define GICR_CTLR_EnableLPI (1<<0)
/** Macro to access the Generic Interrupt Controller Interface (GICC)
*/
#define GIC_CPU_CTRL(hw_base) __REG32((hw_base) + 0x00U)
#define GIC_CPU_PRIMASK(hw_base) __REG32((hw_base) + 0x04U)
#define GIC_CPU_BINPOINT(hw_base) __REG32((hw_base) + 0x08U)
#define GIC_CPU_INTACK(hw_base) __REG32((hw_base) + 0x0cU)
#define GIC_CPU_EOI(hw_base) __REG32((hw_base) + 0x10U)
#define GIC_CPU_RUNNINGPRI(hw_base) __REG32((hw_base) + 0x14U)
#define GIC_CPU_HIGHPRI(hw_base) __REG32((hw_base) + 0x18U)
#define GIC_CPU_IIDR(hw_base) __REG32((hw_base) + 0xFCU)
/** Macro to access the Generic Interrupt Controller Distributor (GICD)
*/
#define GIC_DIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
#define GIC_DIST_TYPE(hw_base) __REG32((hw_base) + 0x004U)
#define GIC_DIST_IGROUP(hw_base, n) __REG32((hw_base) + 0x080U + ((n)/32U) * 4U)
#define GIC_DIST_ENABLE_SET(hw_base, n) __REG32((hw_base) + 0x100U + ((n)/32U) * 4U)
#define GIC_DIST_ENABLE_CLEAR(hw_base, n) __REG32((hw_base) + 0x180U + ((n)/32U) * 4U)
#define GIC_DIST_PENDING_SET(hw_base, n) __REG32((hw_base) + 0x200U + ((n)/32U) * 4U)
#define GIC_DIST_PENDING_CLEAR(hw_base, n) __REG32((hw_base) + 0x280U + ((n)/32U) * 4U)
#define GIC_DIST_ACTIVE_SET(hw_base, n) __REG32((hw_base) + 0x300U + ((n)/32U) * 4U)
#define GIC_DIST_ACTIVE_CLEAR(hw_base, n) __REG32((hw_base) + 0x380U + ((n)/32U) * 4U)
#define GIC_DIST_PRI(hw_base, n) __REG32((hw_base) + 0x400U + ((n)/4U) * 4U)
#define GIC_DIST_TARGET(hw_base, n) __REG32((hw_base) + 0x800U + ((n)/4U) * 4U)
#define GIC_DIST_CONFIG(hw_base, n) __REG32((hw_base) + 0xc00U + ((n)/16U) * 4U)
#define GIC_DIST_SOFTINT(hw_base) __REG32((hw_base) + 0xf00U)
#define GIC_DIST_CPENDSGI(hw_base, n) __REG32((hw_base) + 0xf10U + ((n)/4U) * 4U)
#define GIC_DIST_SPENDSGI(hw_base, n) __REG32((hw_base) + 0xf20U + ((n)/4U) * 4U)
#define GIC_DIST_ICPIDR2(hw_base) __REG32((hw_base) + 0xfe8U)
#define GIC_DIST_IROUTER_LOW(hw_base, n) __REG32((hw_base) + 0x6000U + (n)*8U)
#define GIC_DIST_IROUTER_HIGH(hw_base, n) __REG32((hw_base) + 0x6000U + (n)*8U + 4)
/* SGI base address is at 64K offset from Redistributor base address */
#define GIC_RSGI_OFFSET 0x10000
/** Macro to access the Generic Interrupt Controller Redistributor (GICD)
*/
#define GIC_RDIST_CTRL(hw_base) __REG32((hw_base) + 0x000U)
#define GIC_RDIST_IIDR(hw_base) __REG32((hw_base) + 0x004U)
#define GIC_RDIST_TYPER(hw_base) __REG32((hw_base) + 0x008U)
#define GIC_RDIST_TSTATUSR(hw_base) __REG32((hw_base) + 0x010U)
#define GIC_RDIST_WAKER(hw_base) __REG32((hw_base) + 0x014U)
#define GIC_RDIST_SETLPIR(hw_base) __REG32((hw_base) + 0x040U)
#define GIC_RDIST_CLRLPIR(hw_base) __REG32((hw_base) + 0x048U)
#define GIC_RDIST_PROPBASER(hw_base) __REG32((hw_base) + 0x070U)
#define GIC_RDIST_PENDBASER(hw_base) __REG32((hw_base) + 0x078U)
#define GIC_RDIST_INVLPIR(hw_base) __REG32((hw_base) + 0x0A0U)
#define GIC_RDIST_INVALLR(hw_base) __REG32((hw_base) + 0x0B0U)
#define GIC_RDIST_SYNCR(hw_base) __REG32((hw_base) + 0x0C0U)
#define GIC_RDISTSGI_IGROUPR0(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x080U + (n)*4U)
#define GIC_RDISTSGI_ISENABLER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x100U)
#define GIC_RDISTSGI_ICENABLER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x180U)
#define GIC_RDISTSGI_ISPENDR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x200U)
#define GIC_RDISTSGI_ICPENDR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x280U)
#define GIC_RDISTSGI_ISACTIVER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x300U)
#define GIC_RDISTSGI_ICACTIVER0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x380U)
#define GIC_RDISTSGI_IPRIORITYR(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0x400U + ((n) / 4U) * 4U)
#define GIC_RDISTSGI_ICFGR0(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xC00U)
#define GIC_RDISTSGI_ICFGR1(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xC04U)
#define GIC_RDISTSGI_IGRPMODR0(hw_base, n) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xD00U + (n)*4)
#define GIC_RDISTSGI_NSACR(hw_base) __REG32((hw_base) + GIC_RSGI_OFFSET + 0xE00U)
#define GIC_RSGI_AFF1_OFFSET 16
#define GIC_RSGI_AFF2_OFFSET 32
#define GIC_RSGI_AFF3_OFFSET 48
rt_uint32_t arm_gic_cpumask_to_affval(rt_uint32_t *cpu_mask, rt_uint32_t *cluster_id, rt_uint32_t *target_list);
rt_uint64_t get_main_cpu_affval(void);
int arm_gic_get_active_irq(rt_uint32_t index);
void arm_gic_ack(rt_uint32_t index, int irq);
void arm_gic_mask(rt_uint32_t index, int irq);
void arm_gic_umask(rt_uint32_t index, int irq);
rt_uint32_t arm_gic_get_pending_irq(rt_uint32_t index, int irq);
void arm_gic_set_pending_irq(rt_uint32_t index, int irq);
void arm_gic_clear_pending_irq(rt_uint32_t index, int irq);
void arm_gic_set_configuration(rt_uint32_t index, int irq, rt_uint32_t config);
rt_uint32_t arm_gic_get_configuration(rt_uint32_t index, int irq);
void arm_gic_clear_active(rt_uint32_t index, int irq);
void arm_gic_set_cpu(rt_uint32_t index, int irq, unsigned int cpumask);
rt_uint32_t arm_gic_get_target_cpu(rt_uint32_t index, int irq);
void arm_gic_set_priority(rt_uint32_t index, int irq, rt_uint32_t priority);
rt_uint32_t arm_gic_get_priority(rt_uint32_t index, int irq);
void arm_gic_set_interface_prior_mask(rt_uint32_t index, rt_uint32_t priority);
rt_uint32_t arm_gic_get_interface_prior_mask(rt_uint32_t index);
void arm_gic_set_binary_point(rt_uint32_t index, rt_uint32_t binary_point);
rt_uint32_t arm_gic_get_binary_point(rt_uint32_t index);
rt_uint32_t arm_gic_get_irq_status(rt_uint32_t index, int irq);
void arm_gic_send_affinity_sgi(rt_uint32_t index, int irq, rt_uint32_t cpu_mask, rt_uint32_t routing_mode);
rt_uint32_t arm_gic_get_high_pending_irq(rt_uint32_t index);
rt_uint32_t arm_gic_get_interface_id(rt_uint32_t index);
void arm_gic_set_group(rt_uint32_t index, int irq, rt_uint32_t group);
rt_uint32_t arm_gic_get_group(rt_uint32_t index, int irq);
int arm_gic_redist_address_set(rt_uint32_t index, rt_uint32_t redist_addr, rt_uint32_t cpu_id);
int arm_gic_cpu_interface_address_set(rt_uint32_t index, rt_uint32_t interface_addr, rt_uint32_t cpu_id);
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);
int arm_gic_redist_init(rt_uint32_t index);
void arm_gic_dump_type(rt_uint32_t index);
void arm_gic_dump(rt_uint32_t index);
void arm_gic_set_system_register_enable_mask(rt_uint32_t index, rt_uint32_t value);
rt_uint32_t arm_gic_get_system_register_enable_mask(rt_uint32_t index);
void arm_gic_secondary_cpu_init(void);
#endif

View File

@@ -0,0 +1,179 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-03-30 huijie.feng first version
*/
#include "cp15.h"
#include <rtdef.h>
/** Set CNTFRQ
* This function assigns the given value to PL1 Physical Timer Counter Frequency Register (CNTFRQ).
* @param value: CNTFRQ Register value to set
*/
static inline void __set_cntfrq(rt_uint32_t value)
{
__set_cp(15, 0, value, 14, 0, 0);
}
/** Get CNTFRQ
* This function returns the value of the PL1 Physical Timer Counter Frequency Register (CNTFRQ).
* return CNTFRQ Register value
*/
static inline rt_uint32_t __get_cntfrq(void)
{
rt_uint32_t result;
__get_cp(15, 0, result, 14, 0 , 0);
return result;
}
/** Set CNTP_TVAL
* This function assigns the given value to PL1 Physical Timer Value Register (CNTP_TVAL).
* param value: CNTP_TVAL Register value to set
*/
static inline void __set_cntp_tval(rt_uint32_t value)
{
__set_cp(15, 0, value, 14, 2, 0);
}
/** Get CNTP_TVAL
* This function returns the value of the PL1 Physical Timer Value Register (CNTP_TVAL).
* return CNTP_TVAL Register value
*/
static inline rt_uint32_t __get_cntp_tval(void)
{
rt_uint32_t result;
__get_cp(15, 0, result, 14, 2, 0);
return result;
}
/** Get CNTPCT
* This function returns the value of the 64 bits PL1 Physical Count Register (CNTPCT).
* return CNTPCT Register value
*/
static inline rt_uint64_t __get_cntpct(void)
{
rt_uint64_t result;
__get_cp64(15, 0, result, 14);
return result;
}
/** Set CNTP_CVAL
* This function assigns the given value to 64bits PL1 Physical Timer CompareValue Register (CNTP_CVAL).
* param value: CNTP_CVAL Register value to set
*/
static inline void __set_cntp_cval(rt_uint64_t value)
{
__set_cp64(15, 2, value, 14);
}
/** Get CNTP_CVAL
* This function returns the value of the 64 bits PL1 Physical Timer CompareValue Register (CNTP_CVAL).
* return CNTP_CVAL Register value
*/
static inline rt_uint64_t __get_cntp_cval(void)
{
rt_uint64_t result;
__get_cp64(15, 2, result, 14);
return result;
}
/** Set CNTP_CTL
* This function assigns the given value to PL1 Physical Timer Control Register (CNTP_CTL).
* param value: CNTP_CTL Register value to set
*/
static inline void __set_cntp_ctl(rt_uint32_t value)
{
__set_cp(15, 0, value, 14, 2, 1);
}
/** Get CNTP_CTL register
* return CNTP_CTL Register value
*/
static inline rt_uint32_t __get_cntp_ctl(void)
{
rt_uint32_t result;
__get_cp(15, 0, result, 14, 2, 1);
return result;
}
/** Configures the frequency the timer shall run at.
* param value The timer frequency in Hz.
*/
void gtimer_set_counter_frequency(rt_uint32_t value)
{
__set_cntfrq(value);
__asm__ volatile ("isb 0xF":::"memory");
}
/** Get the frequency the timer shall run at.
* return timer frequency in Hz.
*/
rt_uint32_t gtimer_get_counter_frequency(void)
{
return(__get_cntfrq());
}
/** Sets the reset value of the timer.
* param value: The value the timer is loaded with.
*/
void gtimer_set_load_value(rt_uint32_t value)
{
__set_cntp_tval(value);
__asm__ volatile ("isb 0xF":::"memory");
}
/** Get the current counter value.
* return Current counter value.
*/
rt_uint32_t gtimer_get_current_value(void)
{
return(__get_cntp_tval());
}
/** Get the current physical counter value.
* return Current physical counter value.
*/
rt_uint64_t gtimer_get_current_physical_value(void)
{
return(__get_cntpct());
}
/** Set the physical compare value.
* param value: New physical timer compare value.
*/
void gtimer_set_physical_compare_value(rt_uint64_t value)
{
__set_cntp_cval(value);
__asm__ volatile ("isb 0xF":::"memory");
}
/** Get the physical compare value.
* return Physical compare value.
*/
rt_uint64_t gtimer_get_physical_compare_value(void)
{
return(__get_cntp_cval());
}
/** Configure the timer by setting the control value.
* param value: New timer control value.
*/
void gtimer_set_control(rt_uint32_t value)
{
__set_cntp_ctl(value);
__asm__ volatile ("isb 0xF":::"memory");
}
/** Get the control value.
* return Control value.
*/
rt_uint32_t gtimer_get_control(void)
{
return(__get_cntp_ctl());
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-03-30 huijie.feng first version
*/
#ifndef __GTIMER_H__
#define __GTIMER_H__
#include <rtdef.h>
void gtimer_set_counter_frequency(rt_uint32_t value);
rt_uint32_t gtimer_get_counter_frequency(void);
void gtimer_set_load_value(rt_uint32_t value);
rt_uint32_t gtimer_get_current_value(void);
rt_uint64_t gtimer_get_current_physical_value(void);
void gtimer_set_physical_compare_value(rt_uint64_t value);
rt_uint64_t gtimer_get_physical_compare_value(void);
void gtimer_set_control(rt_uint32_t value);
rt_uint32_t gtimer_get_control(void);
#endif

View File

@@ -0,0 +1,341 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-06 Bernard first version
* 2018-11-22 Jesven add smp support
*/
#include <rthw.h>
#include <rtthread.h>
#include "interrupt.h"
#ifdef RT_USING_GIC_V2
#include "gic.h"
#else
#include "gicv3.h"
#endif
/* exception and interrupt handler table */
struct rt_irq_desc isr_table[MAX_HANDLERS];
#ifndef RT_USING_SMP
/* Those varibles will be accessed in ISR, so we need to share them. */
rt_uint32_t rt_interrupt_from_thread = 0;
rt_uint32_t rt_interrupt_to_thread = 0;
rt_uint32_t rt_thread_switch_interrupt_flag = 0;
#ifdef RT_USING_HOOK
static void (*rt_interrupt_switch_hook)(void);
void rt_interrupt_switch_sethook(void (*hook)(void))
{
rt_interrupt_switch_hook = hook;
}
#endif
void rt_interrupt_hook(void)
{
RT_OBJECT_HOOK_CALL(rt_interrupt_switch_hook, ());
}
#endif
const unsigned int VECTOR_BASE = 0x00;
extern void rt_cpu_vector_set_base(unsigned int addr);
extern int system_vectors;
void rt_hw_vector_init(void)
{
rt_cpu_vector_set_base((unsigned int)&system_vectors);
}
#ifdef RT_USING_GIC_V2
/**
* This function will initialize hardware interrupt
*/
void rt_hw_interrupt_init(void)
{
rt_uint32_t gic_cpu_base;
rt_uint32_t gic_dist_base;
rt_uint32_t gic_irq_start;
/* initialize vector table */
rt_hw_vector_init();
/* initialize exceptions table */
rt_memset(isr_table, 0x00, sizeof(isr_table));
/* initialize ARM GIC */
#ifdef RT_USING_SMART
gic_dist_base = (uint32_t)rt_ioremap((void*)platform_get_gic_dist_base(), 0x2000);
gic_cpu_base = (uint32_t)rt_ioremap((void*)platform_get_gic_cpu_base(), 0x1000);
#else
gic_dist_base = platform_get_gic_dist_base();
gic_cpu_base = platform_get_gic_cpu_base();
#endif
gic_irq_start = GIC_IRQ_START;
arm_gic_dist_init(0, gic_dist_base, gic_irq_start);
arm_gic_cpu_init(0, gic_cpu_base);
}
#else
/**
* This function will initialize hardware interrupt
* Called by the primary cpu(cpu0)
*/
void rt_hw_interrupt_init(void)
{
rt_uint32_t gic_dist_base;
rt_uint32_t gic_irq_start;
/* initialize vector table */
rt_hw_vector_init();
/* initialize exceptions table */
rt_memset(isr_table, 0x00, sizeof(isr_table));
/* initialize ARM GIC */
#ifdef RT_USING_SMART
gic_dist_base = (uint32_t)rt_ioremap((void*)platform_get_gic_dist_base(), 0x10000);
#else
gic_dist_base = platform_get_gic_dist_base();
#endif
gic_irq_start = GIC_IRQ_START;
arm_gic_dist_init(0, gic_dist_base, gic_irq_start);
arm_gic_cpu_init(0);
arm_gic_redist_init(0);
}
#endif
/**
* 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 returns the active interrupt number.
* @param none
*/
int rt_hw_interrupt_get_irq(void)
{
return arm_gic_get_active_irq(0);
}
/**
* This function acknowledges the interrupt.
* @param vector the interrupt number
*/
void rt_hw_interrupt_ack(int vector)
{
arm_gic_ack(0, vector);
}
/**
* This function set interrupt CPU targets.
* @param vector: the interrupt number
* cpu_mask: target cpus mask, one bit for one core
*/
void rt_hw_interrupt_set_target_cpus(int vector, unsigned int cpu_mask)
{
arm_gic_set_cpu(0, vector, cpu_mask);
}
/**
* This function get interrupt CPU targets.
* @param vector: the interrupt number
* @return target cpus mask, one bit for one core
*/
unsigned int rt_hw_interrupt_get_target_cpus(int vector)
{
return arm_gic_get_target_cpu(0, vector);
}
/**
* This function set interrupt triger mode.
* @param vector: the interrupt number
* mode: interrupt triger mode; 0: level triger, 1: edge triger
*/
void rt_hw_interrupt_set_triger_mode(int vector, unsigned int mode)
{
arm_gic_set_configuration(0, vector, mode & IRQ_MODE_MASK);
}
/**
* This function get interrupt triger mode.
* @param vector: the interrupt number
* @return interrupt triger mode; 0: level triger, 1: edge triger
*/
unsigned int rt_hw_interrupt_get_triger_mode(int vector)
{
return arm_gic_get_configuration(0, vector);
}
/**
* This function set interrupt pending flag.
* @param vector: the interrupt number
*/
void rt_hw_interrupt_set_pending(int vector)
{
arm_gic_set_pending_irq(0, vector);
}
/**
* This function get interrupt pending flag.
* @param vector: the interrupt number
* @return interrupt pending flag, 0: not pending; 1: pending
*/
unsigned int rt_hw_interrupt_get_pending(int vector)
{
return arm_gic_get_pending_irq(0, vector);
}
/**
* This function clear interrupt pending flag.
* @param vector: the interrupt number
*/
void rt_hw_interrupt_clear_pending(int vector)
{
arm_gic_clear_pending_irq(0, vector);
}
/**
* This function set interrupt priority value.
* @param vector: the interrupt number
* priority: the priority of interrupt to set
*/
void rt_hw_interrupt_set_priority(int vector, unsigned int priority)
{
arm_gic_set_priority(0, vector, priority);
}
/**
* This function get interrupt priority.
* @param vector: the interrupt number
* @return interrupt priority value
*/
unsigned int rt_hw_interrupt_get_priority(int vector)
{
return arm_gic_get_priority(0, vector);
}
/**
* This function set priority masking threshold.
* @param priority: priority masking threshold
*/
void rt_hw_interrupt_set_priority_mask(unsigned int priority)
{
arm_gic_set_interface_prior_mask(0, priority);
}
/**
* This function get priority masking threshold.
* @param none
* @return priority masking threshold
*/
unsigned int rt_hw_interrupt_get_priority_mask(void)
{
return arm_gic_get_interface_prior_mask(0);
}
/**
* This function set priority grouping field split point.
* @param bits: priority grouping field split point
* @return 0: success; -1: failed
*/
int rt_hw_interrupt_set_prior_group_bits(unsigned int bits)
{
int status;
if (bits < 8)
{
arm_gic_set_binary_point(0, (7 - bits));
status = 0;
}
else
{
status = -1;
}
return (status);
}
/**
* This function get priority grouping field split point.
* @param none
* @return priority grouping field split point
*/
unsigned int rt_hw_interrupt_get_prior_group_bits(void)
{
unsigned int bp;
bp = arm_gic_get_binary_point(0) & 0x07;
return (7 - bp);
}
/**
* 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, const 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;
}
#ifdef RT_USING_SMP
void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask)
{
#ifdef RT_USING_GIC_V2
arm_gic_send_sgi(0, ipi_vector, cpu_mask, 0);
#else
arm_gic_send_affinity_sgi(0, ipi_vector, cpu_mask, ROUTED_TO_SPEC);
#endif
}
void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler)
{
/* note: ipi_vector maybe different with irq_vector */
rt_hw_interrupt_install(ipi_vector, ipi_isr_handler, 0, "IPI_HANDLER");
}
#endif

View File

@@ -0,0 +1,61 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-06 Bernard first version
*/
#ifndef __INTERRUPT_H__
#define __INTERRUPT_H__
#include <rthw.h>
#include <board.h>
#define INT_IRQ 0x00
#define INT_FIQ 0x01
#define IRQ_MODE_TRIG_LEVEL (0x00) /* Trigger: level triggered interrupt */
#define IRQ_MODE_TRIG_EDGE (0x01) /* Trigger: edge triggered interrupt */
#define IRQ_MODE_MASK (0x01)
void rt_hw_vector_init(void);
void rt_hw_interrupt_init(void);
void rt_hw_interrupt_mask(int vector);
void rt_hw_interrupt_umask(int vector);
int rt_hw_interrupt_get_irq(void);
void rt_hw_interrupt_ack(int vector);
void rt_hw_interrupt_set_target_cpus(int vector, unsigned int cpu_mask);
unsigned int rt_hw_interrupt_get_target_cpus(int vector);
void rt_hw_interrupt_set_triger_mode(int vector, unsigned int mode);
unsigned int rt_hw_interrupt_get_triger_mode(int vector);
void rt_hw_interrupt_set_pending(int vector);
unsigned int rt_hw_interrupt_get_pending(int vector);
void rt_hw_interrupt_clear_pending(int vector);
void rt_hw_interrupt_set_priority(int vector, unsigned int priority);
unsigned int rt_hw_interrupt_get_priority(int vector);
void rt_hw_interrupt_set_priority_mask(unsigned int priority);
unsigned int rt_hw_interrupt_get_priority_mask(void);
int rt_hw_interrupt_set_prior_group_bits(unsigned int bits);
unsigned int rt_hw_interrupt_get_prior_group_bits(void);
rt_isr_handler_t rt_hw_interrupt_install(int vector, rt_isr_handler_t handler,
void *param, const char *name);
#ifdef RT_USING_SMP
void rt_hw_ipi_send(int ipi_vector, unsigned int cpu_mask);
void rt_hw_ipi_handler_install(int ipi_vector, rt_isr_handler_t ipi_isr_handler);
#endif
#endif

View File

@@ -0,0 +1,503 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2012-01-10 bernard porting to AM1808
* 2023-10-10 Shell Add permission control API
*/
#include <rthw.h>
#include <rtthread.h>
#define DBG_TAG "hw.mmu"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#include <board.h>
#include "cp15.h"
#include "mm_page.h"
#include "mmu.h"
#include <mm_aspace.h>
#include <tlb.h>
#ifdef RT_USING_SMART
#include <lwp_mm.h>
#include <lwp_arch.h>
#include "ioremap.h"
#else
#define KERNEL_VADDR_START 0
#endif
/* level1 page table, each entry for 1MB memory. */
volatile unsigned long MMUTable[4 * 1024] __attribute__((aligned(16 * 1024)));
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_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++;
}
}
void init_mm_setup(unsigned int *mtbl, unsigned int size, unsigned int pv_off)
{
unsigned int va;
for (va = 0; va < 0x1000; va++)
{
unsigned int vaddr = (va << 20);
if (vaddr >= KERNEL_VADDR_START && vaddr - KERNEL_VADDR_START < size)
{
mtbl[va] = ((va << 20) + pv_off) | NORMAL_MEM;
}
else if (vaddr >= (KERNEL_VADDR_START + pv_off) && vaddr - (KERNEL_VADDR_START + pv_off) < size)
{
mtbl[va] = (va << 20) | NORMAL_MEM;
}
else
{
mtbl[va] = 0;
}
}
}
#ifndef RT_USING_SMART
static void _init_map_section(rt_uint32_t *mmu_table, rt_uint32_t va,
rt_uint32_t size,rt_uint32_t pa, rt_uint32_t attr)
{
volatile rt_uint32_t *ptt;
volatile int i, num_section;
ptt = (rt_uint32_t *)mmu_table + (va >> ARCH_SECTION_SHIFT);
num_section = size >> ARCH_SECTION_SHIFT;
for(i = 0; i <= num_section; i++)
{
*ptt = attr | (((pa >> ARCH_SECTION_SHIFT) + i) << ARCH_SECTION_SHIFT);
ptt++;
}
}
#endif
void rt_hw_mem_setup_early(rt_uint32_t *early_mmu_talbe,
rt_uint32_t pv_off)
{
rt_uint32_t size = 0;
size = 0x100000 + (rt_uint32_t)&__bss_end;
size &= ~(0x100000 - 1);
#ifdef RT_USING_SMART
size -= KERNEL_VADDR_START;
init_mm_setup(early_mmu_talbe, size, pv_off);
#else
rt_uint32_t normal_attr = NORMAL_MEM;
extern unsigned char _reset;
rt_uint32_t va = (rt_uint32_t) &_reset;
/* The starting virtual address is aligned along 0x1000000. */
va &= (0x1000000 - 1);
size -= va;
_init_map_section(early_mmu_talbe, va, size, va + pv_off, normal_attr);
#endif
}
void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size)
{
void *vaddr;
size_t length;
/* init kernel space */
#ifdef RT_USING_SMART
rt_aspace_init(&rt_kernel_space, (void *)USER_VADDR_TOP, -USER_VADDR_TOP, (void *)MMUTable);
#else
rt_aspace_init(&rt_kernel_space, (void *)0x1000, 0 - 0x1000, (void *)MMUTable);
#endif /* RT_USING_SMART */
/* set page table */
for(; size > 0; size--)
{
if (mdesc->paddr_start == (rt_uint32_t)ARCH_MAP_FAILED)
mdesc->paddr_start = mdesc->vaddr_start + PV_OFFSET;
vaddr = (void *)mdesc->vaddr_start;
length = mdesc->vaddr_end - mdesc->vaddr_start;
rt_aspace_map_static(&rt_kernel_space, &mdesc->varea, &vaddr, length,
mdesc->attr, MMF_MAP_FIXED, &rt_mm_dummy_mapper, 0);
rt_hw_mmu_setmtt(mdesc->vaddr_start, mdesc->vaddr_end,
mdesc->paddr_start, mdesc->attr);
mdesc++;
}
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, (void*)MMUTable, sizeof MMUTable);
}
void rt_hw_mmu_init(void)
{
rt_cpu_dcache_clean_flush();
rt_cpu_icache_flush();
rt_hw_cpu_dcache_disable();
rt_hw_cpu_icache_disable();
rt_cpu_mmu_disable();
/*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();
}
int rt_hw_mmu_map_init(struct rt_aspace *aspace, void* v_address, size_t size, size_t *vtable, size_t pv_off)
{
size_t l1_off, va_s, va_e;
if (!aspace || !vtable)
{
return -1;
}
va_s = (size_t)v_address;
va_e = (size_t)v_address + size - 1;
if ( va_e < va_s)
{
return -1;
}
va_s >>= ARCH_SECTION_SHIFT;
va_e >>= ARCH_SECTION_SHIFT;
if (va_s == 0)
{
return -1;
}
for (l1_off = va_s; l1_off <= va_e; l1_off++)
{
size_t v = vtable[l1_off];
if (v & ARCH_MMU_USED_MASK)
{
return -1;
}
}
#ifdef RT_USING_SMART
rt_ioremap_start = v_address;
rt_ioremap_size = size;
rt_mpr_start = rt_ioremap_start - rt_mpr_size;
#else
rt_mpr_start = (void *)((rt_size_t)0 - rt_mpr_size);
#endif
return 0;
}
int rt_hw_mmu_ioremap_init(rt_aspace_t aspace, void* v_address, size_t size)
{
#ifdef RT_IOREMAP_LATE
size_t loop_va;
size_t l1_off;
size_t *mmu_l1, *mmu_l2;
size_t sections;
/* for kernel ioremap */
if ((size_t)v_address < KERNEL_VADDR_START)
{
return -1;
}
/* must align to section */
if ((size_t)v_address & ARCH_SECTION_MASK)
{
return -1;
}
/* must align to section */
if (size & ARCH_SECTION_MASK)
{
return -1;
}
loop_va = (size_t)v_address;
sections = (size >> ARCH_SECTION_SHIFT);
while (sections--)
{
l1_off = (loop_va >> ARCH_SECTION_SHIFT);
mmu_l1 = (size_t*)aspace->page_table + l1_off;
RT_ASSERT((*mmu_l1 & ARCH_MMU_USED_MASK) == 0);
mmu_l2 = (size_t*)rt_pages_alloc(0);
if (mmu_l2)
{
rt_memset(mmu_l2, 0, ARCH_PAGE_TBL_SIZE * 2);
/* cache maintain */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2, ARCH_PAGE_TBL_SIZE);
*mmu_l1 = (((size_t)mmu_l2 + PV_OFFSET) | 0x1);
/* cache maintain */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l1, 4);
}
else
{
/* error */
return -1;
}
loop_va += ARCH_SECTION_SIZE;
}
#endif
return 0;
}
static void _kenrel_unmap_4K(unsigned long *lv0_tbl, void *v_addr)
{
size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK;
size_t l1_off, l2_off;
size_t *mmu_l1, *mmu_l2;
l1_off = (loop_va >> ARCH_SECTION_SHIFT);
l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
mmu_l1 = (size_t *)lv0_tbl + l1_off;
if (*mmu_l1 & ARCH_MMU_USED_MASK)
{
mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - PV_OFFSET);
}
else
{
return;
}
if (*(mmu_l2 + l2_off) & ARCH_MMU_USED_MASK)
{
*(mmu_l2 + l2_off) = 0;
/* cache maintain */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2 + l2_off, 4);
if (rt_pages_free(mmu_l2, 0))
{
*mmu_l1 = 0;
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l1, 4);
}
}
loop_va += ARCH_PAGE_SIZE;
}
static int _kenrel_map_4K(unsigned long *lv0_tbl, void *v_addr, void *p_addr,
size_t attr)
{
size_t loop_va = (size_t)v_addr & ~ARCH_PAGE_MASK;
size_t loop_pa = (size_t)p_addr & ~ARCH_PAGE_MASK;
size_t l1_off, l2_off;
size_t *mmu_l1, *mmu_l2;
l1_off = (loop_va >> ARCH_SECTION_SHIFT);
l2_off = ((loop_va & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
mmu_l1 = (size_t *)lv0_tbl + l1_off;
if (*mmu_l1 & ARCH_MMU_USED_MASK)
{
mmu_l2 = (size_t *)((*mmu_l1 & ~ARCH_PAGE_TBL_MASK) - PV_OFFSET);
rt_page_ref_inc(mmu_l2, 0);
}
else
{
mmu_l2 = (size_t *)rt_pages_alloc(0);
if (mmu_l2)
{
rt_memset(mmu_l2, 0, ARCH_PAGE_TBL_SIZE * 2);
/* cache maintain */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2, ARCH_PAGE_TBL_SIZE);
*mmu_l1 = (((size_t)mmu_l2 + PV_OFFSET) | 0x1);
/* cache maintain */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l1, 4);
}
else
{
/* error, quit */
return -1;
}
}
*(mmu_l2 + l2_off) = (loop_pa | attr);
/* cache maintain */
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_l2 + l2_off, 4);
loop_va += ARCH_PAGE_SIZE;
loop_pa += ARCH_PAGE_SIZE;
return 0;
}
void *rt_hw_mmu_map(rt_aspace_t aspace, void *v_addr, void *p_addr, size_t size,
size_t attr)
{
int ret = -1;
void *unmap_va = v_addr;
size_t npages = size >> ARCH_PAGE_SHIFT;
// TODO trying with HUGEPAGE here
while (npages--)
{
ret = _kenrel_map_4K(aspace->page_table, v_addr, p_addr, attr);
if (ret != 0)
{
/* error, undo map */
while (unmap_va != v_addr)
{
rt_enter_critical();
_kenrel_unmap_4K(aspace->page_table, (void *)unmap_va);
rt_exit_critical();
unmap_va += ARCH_PAGE_SIZE;
}
break;
}
v_addr += ARCH_PAGE_SIZE;
p_addr += ARCH_PAGE_SIZE;
}
if (ret == 0)
{
return v_addr;
}
return NULL;
}
void rt_hw_mmu_unmap(rt_aspace_t aspace, void *v_addr, size_t size)
{
// caller guarantee that v_addr & size are page aligned
size_t npages = size >> ARCH_PAGE_SHIFT;
if (!aspace->page_table)
{
return;
}
while (npages--)
{
rt_enter_critical();
_kenrel_unmap_4K(aspace->page_table, v_addr);
rt_exit_critical();
v_addr += ARCH_PAGE_SIZE;
}
}
void rt_hw_aspace_switch(rt_aspace_t aspace)
{
if (aspace != &rt_kernel_space)
{
void *pgtbl = aspace->page_table;
pgtbl = rt_kmem_v2p(pgtbl);
rt_hw_mmu_switch(pgtbl);
rt_hw_tlb_invalidate_all_local();
}
}
void *rt_hw_mmu_v2p(rt_aspace_t aspace, void* v_addr)
{
size_t l1_off, l2_off;
size_t *mmu_l1, *mmu_l2;
size_t tmp;
size_t pa;
l1_off = (size_t)v_addr >> ARCH_SECTION_SHIFT;
RT_ASSERT(aspace);
mmu_l1 = (size_t*)aspace->page_table + l1_off;
tmp = *mmu_l1;
switch (tmp & ARCH_MMU_USED_MASK)
{
case 0: /* not used */
break;
case 1: /* page table */
mmu_l2 = (size_t *)((tmp & ~ARCH_PAGE_TBL_MASK) - PV_OFFSET);
l2_off = (((size_t)v_addr & ARCH_SECTION_MASK) >> ARCH_PAGE_SHIFT);
pa = *(mmu_l2 + l2_off);
if (pa & ARCH_MMU_USED_MASK)
{
if ((pa & ARCH_MMU_USED_MASK) == 1)
{
/* large page, not support */
break;
}
pa &= ~(ARCH_PAGE_MASK);
pa += ((size_t)v_addr & ARCH_PAGE_MASK);
return (void*)pa;
}
break;
case 2:
case 3:
/* section */
if (tmp & ARCH_TYPE_SUPERSECTION)
{
/* super section, not support */
break;
}
pa = (tmp & ~ARCH_SECTION_MASK);
pa += ((size_t)v_addr & ARCH_SECTION_MASK);
return (void*)pa;
}
return ARCH_MAP_FAILED;
}
int rt_hw_mmu_control(struct rt_aspace *aspace, void *vaddr, size_t size,
enum rt_mmu_cntl cmd)
{
return -RT_ENOSYS;
}
#define KPTE_START (KERNEL_VADDR_START >> ARCH_SECTION_SHIFT)
void *rt_hw_mmu_pgtbl_create(void)
{
size_t *mmu_table;
mmu_table = (size_t *)rt_pages_alloc_ext(2, PAGE_ANY_AVAILABLE);
if (!mmu_table)
{
return RT_NULL;
}
rt_memcpy(mmu_table + KPTE_START, (size_t *)rt_kernel_space.page_table + KPTE_START, ARCH_PAGE_SIZE);
rt_memset(mmu_table, 0, 3 * ARCH_PAGE_SIZE);
rt_hw_cpu_dcache_ops(RT_HW_CACHE_FLUSH, mmu_table, 4 * ARCH_PAGE_SIZE);
return mmu_table;
}
void rt_hw_mmu_pgtbl_delete(void *pgtbl)
{
rt_pages_free(pgtbl, 2);
}

View File

@@ -0,0 +1,215 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-03-25 quanzhao the first version
* 2023-10-10 Shell Add permission control API
*/
#ifndef __MMU_H_
#define __MMU_H_
#include <rtthread.h>
#include <mm_aspace.h>
#define DESC_SEC (0x2)
#define MEMWBWA ((1<<12)|(3<<2)) /* write back, write allocate */
#define MEMWB (3<<2) /* write back, no write allocate */
#define MEMWT (2<<2) /* write through, no write allocate */
#define SHAREDEVICE (1<<2) /* shared device */
#define STRONGORDER (0<<2) /* strong ordered */
#define XN (1<<4) /* eXecute Never */
#ifdef RT_USING_SMART
#define AP_RW (1<<10) /* supervisor=RW, user=No */
#define AP_RO ((1<<10) |(1 << 15)) /* supervisor=RW, user=No */
#else
#define AP_RW (3<<10) /* supervisor=RW, user=RW */
#define AP_RO (2<<10) /* supervisor=RW, user=RO */
#endif
#define SHARED (1<<16) /* shareable */
#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)
/* device mapping type */
#define DEVICE_MEM (SHARED|AP_RW|DOMAIN0|SHAREDEVICE|DESC_SEC|XN)
/* normal memory mapping type */
#define NORMAL_MEM (SHARED|AP_RW|DOMAIN0|MEMWBWA|DESC_SEC)
#define STRONG_ORDER_MEM (SHARED|AP_RO|XN|DESC_SEC)
struct mem_desc
{
rt_uint32_t vaddr_start;
rt_uint32_t vaddr_end;
rt_uint32_t paddr_start;
rt_uint32_t attr;
struct rt_varea varea;
};
#define MMU_MAP_MTBL_XN (1<<0)
#define MMU_MAP_MTBL_A (1<<1)
#define MMU_MAP_MTBL_B (1<<2)
#define MMU_MAP_MTBL_C (1<<3)
#define MMU_MAP_MTBL_AP01(x) (x<<4)
#define MMU_MAP_MTBL_TEX(x) (x<<6)
#define MMU_MAP_MTBL_AP2(x) (x<<9)
#define MMU_MAP_MTBL_SHARE (1<<10)
#define MMU_MAP_MTBL_NG(x) (x<<11)
#define MMU_MAP_K_ROCB ((MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(1)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_K_RO ((MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(1)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_K_RWCB ((MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_K_RW ((MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_K_DEVICE ((MMU_MAP_MTBL_NG(0))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(1)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_U_ROCB ((MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(2)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_U_RO ((MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(2)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_U_RWCB ((MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(3)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_C|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_U_RW ((MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(3)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_U_DEVICE ((MMU_MAP_MTBL_NG(1))|(MMU_MAP_MTBL_A|MMU_MAP_MTBL_AP2(0)|MMU_MAP_MTBL_AP01(3)|MMU_MAP_MTBL_TEX(0)|MMU_MAP_MTBL_B|MMU_MAP_MTBL_SHARE))
#define MMU_MAP_TRACE(attr) (attr)
#define ARCH_SECTION_SHIFT 20
#define ARCH_SECTION_SIZE (1 << ARCH_SECTION_SHIFT)
#define ARCH_SECTION_MASK (ARCH_SECTION_SIZE - 1)
#define ARCH_PAGE_SHIFT 12
#define ARCH_PAGE_SIZE (1 << ARCH_PAGE_SHIFT)
#define ARCH_PAGE_MASK (ARCH_PAGE_SIZE - 1)
#define ARCH_PAGE_TBL_SHIFT 10
#define ARCH_PAGE_TBL_SIZE (1 << ARCH_PAGE_TBL_SHIFT)
#define ARCH_PAGE_TBL_MASK (ARCH_PAGE_TBL_SIZE - 1)
#define ARCH_MMU_USED_MASK 3
#define ARCH_TYPE_SUPERSECTION (1 << 18)
#define ARCH_ADDRESS_WIDTH_BITS 32
#define ARCH_VADDR_WIDTH 32
/**
* *info it's possible to map (-1ul & ~ARCH_PAGE_MASK) but a not aligned -1 is
* never returned on a successful mapping
*/
#define ARCH_MAP_FAILED ((void *)-1)
#define RT_HW_MMU_PROT_READ 1
#define RT_HW_MMU_PROT_WRITE 2
#define RT_HW_MMU_PROT_EXECUTE 4
#define RT_HW_MMU_PROT_KERNEL 8
#define RT_HW_MMU_PROT_USER 16
#define RT_HW_MMU_PROT_CACHE 32
int rt_hw_mmu_ioremap_init(struct rt_aspace *aspace, void *v_address, size_t size);
void rt_hw_init_mmu_table(struct mem_desc *mdesc, rt_uint32_t size);
void rt_hw_mmu_setup(struct rt_aspace *aspace, struct mem_desc *mdesc, int desc_nr);
void rt_hw_mmu_init(void);
int rt_hw_mmu_map_init(struct rt_aspace *aspace, void *v_address, size_t size, size_t *vtable, size_t pv_off);
void *rt_hw_mmu_map(struct rt_aspace *aspace, void *v_addr, void *p_addr, size_t size, size_t attr);
void rt_hw_mmu_unmap(struct rt_aspace *aspace, void *v_addr, size_t size);
void rt_hw_aspace_switch(struct rt_aspace *aspace);
void rt_hw_mmu_switch(void *tbl);
void *rt_hw_mmu_v2p(struct rt_aspace *aspace, void *vaddr);
void rt_hw_mmu_kernel_map_init(struct rt_aspace *aspace, size_t vaddr_start, size_t size);
void *rt_hw_mmu_tbl_get(void);
int rt_hw_mmu_control(struct rt_aspace *aspace, void *vaddr, size_t size, enum rt_mmu_cntl cmd);
void *rt_hw_mmu_pgtbl_create(void);
void rt_hw_mmu_pgtbl_delete(void *pgtbl);
#define AP_APX_MASK (MMU_MAP_MTBL_AP2(0x1) | MMU_MAP_MTBL_AP01(0x3))
#define AP_APX_URW_KRW (MMU_MAP_MTBL_AP2(0x0) | MMU_MAP_MTBL_AP01(0x3))
#define AP_APX_URO_KRO (MMU_MAP_MTBL_AP2(0x1) | MMU_MAP_MTBL_AP01(0x2))
/**
* @brief Remove permission from attribution
*
* @param attr architecture specified mmu attribution
* @param prot protect that will be removed
* @return size_t returned attribution
*/
rt_inline size_t rt_hw_mmu_attr_rm_perm(size_t attr, rt_base_t prot)
{
switch (prot)
{
/* remove write permission for user */
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER:
if ((attr & AP_APX_MASK) == AP_APX_URW_KRW)
attr &= ~MMU_MAP_MTBL_AP01(0x1);
break;
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_KERNEL:
switch (attr & AP_APX_MASK)
{
case MMU_MAP_MTBL_AP01(0):
break;
case MMU_MAP_MTBL_AP01(3):
attr = (attr & AP_APX_MASK) | AP_APX_URO_KRO;
default:
attr |= MMU_MAP_MTBL_AP2(0x1);
break;
}
break;
default:
RT_ASSERT(0);
}
return attr;
}
/**
* @brief Add permission from attribution
*
* @param attr architecture specified mmu attribution
* @param prot protect that will be added
* @return size_t returned attribution
*/
rt_inline size_t rt_hw_mmu_attr_add_perm(size_t attr, rt_base_t prot)
{
switch (prot)
{
/* add write permission for user */
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER:
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_KERNEL:
attr |= MMU_MAP_MTBL_AP01(0x3);
attr &= ~MMU_MAP_MTBL_AP2(0x1);
break;
default:
RT_ASSERT(0);
}
return attr;
}
/**
* @brief Test permission from attribution
*
* @param attr architecture specified mmu attribution
* @param prot protect that will be test
* @return rt_bool_t RT_TRUE if the prot is allowed, otherwise RT_FALSE
*/
rt_inline rt_bool_t rt_hw_mmu_attr_test_perm(size_t attr, rt_base_t prot)
{
rt_bool_t rc = 0;
switch (prot)
{
/* test write permission for user */
case RT_HW_MMU_PROT_WRITE | RT_HW_MMU_PROT_USER:
rc = (AP_APX_MASK & attr) == (AP_APX_URW_KRW);
break;
default:
RT_ASSERT(0);
}
return rc;
}
#endif

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#include <rtthread.h>
#include "pmu.h"
#define DBG_TAG "PMU"
#define DBG_LVL DBG_WARNING
#include <rtdbg.h>
void rt_hw_pmu_dump_feature(void)
{
unsigned long reg;
reg = rt_hw_pmu_get_control();
LOG_D("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));
RT_UNUSED(reg);
}

View File

@@ -0,0 +1,159 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
*/
#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__ */

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2011-09-23 Bernard the first version
* 2011-10-05 Bernard add thumb mode
*/
#include <rtthread.h>
#include <cpuport.h>
#include <board.h>
/**
* @addtogroup ARM Cortex-A
*/
/*@{*/
/**
* 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;
stack_addr += sizeof(rt_uint32_t);
stack_addr = (rt_uint8_t *)RT_ALIGN_DOWN((rt_uint32_t)stack_addr, 8);
stk = (rt_uint32_t *)stack_addr;
*(--stk) = (rt_uint32_t)_thread_start; /* entry point */
*(--stk) = (rt_uint32_t)texit; /* lr */
*(--stk) = 0xdeadbeef; /* r12 */
*(--stk) = 0xdeadbeef; /* r11 */
*(--stk) = 0xdeadbeef; /* r10 */
*(--stk) = 0xdeadbeef; /* r9 */
*(--stk) = 0xdeadbeef; /* r8 */
*(--stk) = 0xdeadbeef; /* r7 */
*(--stk) = 0xdeadbeef; /* r6 */
*(--stk) = 0xdeadbeef; /* r5 */
*(--stk) = 0xdeadbeef; /* r4 */
*(--stk) = 0xdeadbeef; /* r3 */
*(--stk) = 0xdeadbeef; /* r2 */
*(--stk) = (rt_uint32_t)tentry; /* r1 : argument 2 for trampoline */
*(--stk) = (rt_uint32_t)parameter; /* r0 : argument 1 */
/* cpsr */
if ((rt_uint32_t)tentry & 0x01)
*(--stk) = SVCMODE | 0x20; /* thumb mode */
else
*(--stk) = SVCMODE; /* arm mode */
#ifdef RT_USING_SMART
*(--stk) = 0; /* user lr */
*(--stk) = 0; /* user sp*/
#endif
#ifdef RT_USING_FPU
*(--stk) = 0; /* not use fpu*/
#endif
/* return task's current stack address */
return (rt_uint8_t *)stk;
}
/*@}*/

View File

@@ -0,0 +1,695 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-05 Bernard the first version
* 2018-11-22 Jesven in the interrupt context, use rt_scheduler_do_irq_switch checks
* and switches to a new thread
* 2024-01-16 huanghe restructure this code section following the aarch64 architectural style
*/
#include "rtconfig.h"
#define ARM_CPU_STACK_SIZE_OFFSET 12
#define ARM_CPU_STACK_SIZE (1<<ARM_CPU_STACK_SIZE_OFFSET)
.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 */
/*Load the physical address of a symbol into a register.
Through pv_off calculates the offset of the physical address */
.macro get_phy, reg, symbol, _pvoff
ldr \reg, =\symbol
add \reg, \_pvoff
.endm
/*Calculate the offset between the physical address and the virtual address of the "_reset".*/
.macro get_pvoff, tmp, out
ldr \tmp, =_reset
adr \out, _reset
sub \out, \out, \tmp
.endm
pv_off .req r11 /* Used to store the offset between physical address and the virtual address */
cpu_id .req r10 /* Used to store the cpu id */
/* reset entry */
.globl _reset
_reset:
/* Calculate the offset between the physical address and the virtual address */
get_pvoff r0, pv_off
/* exit hyp mode */
bl init_cpu_mode
/* clear bss section */
bl init_kernel_bss
/* Initializes the assembly environment stack */
bl init_cpu_stack_early
/* init mmu */
b init_mmu_page_table_early
init_cpu_stack_early:
cps #Mode_SVC
get_phy r0, svc_stack_top, pv_off
mov sp, r0
#ifdef RT_USING_FPU
mov r4, #0xfffffff
mcr p15, 0, r4, c1, c0, 2
#endif
mov pc, lr
init_kernel_bss:
/* enable I cache + branch prediction */
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #(1<<12)
orr r0, r0, #(1<<11)
mcr p15, 0, r0, c1, c0, 0
mov r0,#0 /* get a zero */
get_phy r1, __bss_start, pv_off
get_phy r2, __bss_end, pv_off
bss_loop:
cmp r1,r2 /* check if data to clear */
strlo r0,[r1],#4 /* clear 4 bytes */
blo bss_loop /* loop until done */
mov pc, lr
init_cpu_mode:
#ifdef ARCH_ARMV8
/* Check for HYP mode */
mrs r0, cpsr_all
and r0, r0, #0x1F
mov r8, #0x1A
cmp r0, r8
beq overHyped
b continue_exit
overHyped: /* Get out of HYP mode */
mov r9, lr
/* HYP mode has a dedicated register, called ELR_hyp,
to store the exception return address.
The lr register needs to be temporarily saved,
otherwise "mov pc lr" cannot be used after switching modes. */
adr r1, continue_exit
msr ELR_hyp, r1
mrs r1, cpsr_all
and r1, r1, #0xFFFFFFE0 /* CPSR_MODE_MASK */
orr r1, r1, #0x13 /* CPSR_MODE_SUPERVISOR */
msr SPSR_hyp, r1
eret
continue_exit:
mov lr ,r9
#endif
#ifdef SOC_BCM283x
/* Suspend the other cpu cores */
mrc p15, 0, r0, c0, c0, 5
ands r0, #3
bne _halt
/* Disable IRQ & FIQ */
cpsid if
/* Check for HYP mode */
mrs r0, cpsr_all
and r0, r0, #0x1F
mov r8, #0x1A
cmp r0, r8
beq overHyped
b continue_exit
overHyped: /* Get out of HYP mode */
mov r9, lr
/* HYP mode has a dedicated register, called ELR_hyp,
to store the exception return address.
The lr register needs to be temporarily saved,
otherwise "mov pc lr" cannot be used after switching modes. */
adr r1, continue_exit
msr ELR_hyp, r1
mrs r1, cpsr_all
and r1, r1, #0xFFFFFFE0 /* CPSR_MODE_MASK */
orr r1, r1, #0x13 /* CPSR_MODE_SUPERVISOR */
msr SPSR_hyp, r1
eret
continue_exit:
mov lr ,r9
/* set the cpu to SVC32 mode and disable interrupt */
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0x13
msr cpsr_c, r0
#endif
/* invalid tlb before enable mmu */
mrc p15, 0, r0, c1, c0, 0
bic r0, #1
mcr p15, 0, r0, c1, c0, 0
dsb
isb
mov r0, #0
mcr p15, 0, r0, c8, c7, 0
mcr p15, 0, r0, c7, c5, 0 /* iciallu */
mcr p15, 0, r0, c7, c5, 6 /* bpiall */
dsb
isb
mov pc, lr
init_mmu_page_table_early:
get_phy r0, init_mtbl, pv_off
mov r1, pv_off
bl rt_hw_mem_setup_early
/* get cpu id */
bl rt_hw_cpu_id_early
mov cpu_id ,r0
/* enable_mmu_page_table_early is changed to master_core_startup */
ldr lr, =master_core_startup
cmp cpu_id, #0
beq enable_mmu_page_table_early
#ifdef RT_USING_SMP
#ifdef RT_SMP_AUTO_BOOT
/* if cpu id > 0, stop or wait */
ldr r0, =secondary_cpu_entry
mov r1, #0
str r1, [r0] /* clean secondary_cpu_entry */
#endif
#endif
secondary_loop:
@ cpu core 1 goes into sleep until core 0 wakeup it
wfe
#ifdef RT_SMP_AUTO_BOOT
ldr r1, =secondary_cpu_entry
ldr r0, [r1]
cmp r0, #0
blxne r0 /* if(secondary_cpu_entry) secondary_cpu_entry(); */
#endif /* RT_SMP_AUTO_BOOT */
b secondary_loop
enable_mmu_page_table_early:
/* init TTBR0 */
get_phy r0, init_mtbl, pv_off
mcr p15, #0, r0, c2, c0, #0
dmb
ldr r0,=#0x55555555
mcr p15, #0, r0, c3, c0, #0
/* disable ttbr1 */
mov r0, #(1 << 5) /* PD1=1 */
mcr p15, 0, r0, c2, c0, 2 /* ttbcr */
/* init stack for cpu mod */
cps #Mode_UND
ldr r1,=und_stack_top
sub sp, r1, cpu_id, asl #ARM_CPU_STACK_SIZE_OFFSET
cps #Mode_IRQ
ldr r1, =irq_stack_top
sub sp, r1, cpu_id, asl #ARM_CPU_STACK_SIZE_OFFSET
cps #Mode_FIQ
ldr r1, =irq_stack_top
sub sp, r1, cpu_id, asl #ARM_CPU_STACK_SIZE_OFFSET
cps #Mode_ABT
ldr r1, =abt_stack_top
sub sp, r1, cpu_id, asl #ARM_CPU_STACK_SIZE_OFFSET
cps #Mode_SVC
ldr r1, =svc_stack_top
sub sp, r1, cpu_id, asl #ARM_CPU_STACK_SIZE_OFFSET
/* invalid tlb before enable mmu */
mov r0, #0
mcr p15, 0, r0, c8, c7, 0
mcr p15, 0, r0, c7, c5, 0 /* iciallu */
mcr p15, 0, r0, c7, c5, 6 /* bpiall */
mrc p15, 0, r0, c1, c0, 0
bic r0, r0, #0x7 /* clear bit1~3 */
orr r0, #((1 << 12) | (1 << 11)) /* instruction cache, branch prediction */
orr r0, #((1 << 2) | (1 << 0)) /* data cache, mmu enable */
mcr p15, 0, r0, c1, c0, 0
dsb
isb
mov pc, lr
master_core_startup :
mov r0 ,pv_off
bl rt_kmem_pvoff_set
ldr lr, =rtthread_startup
mov pc, lr
.global rt_hw_mmu_tbl_get
rt_hw_mmu_tbl_get:
mrc p15, 0, r0, c2, c0, 0 /* ttbr0 */
bic r0, #0x18
mov pc, lr
.weak rt_hw_cpu_id_early
rt_hw_cpu_id_early:
mrc p15, 0, r0, c0, c0, 5
and r0, r0, #0xf
mov pc, lr
#ifdef RT_USING_SMP
.global rt_secondary_cpu_entry
rt_secondary_cpu_entry:
ldr r0, =_reset
adr pv_off, _reset
sub pv_off, pv_off, r0
bl init_cpu_stack_early
/* init mmu */
bl rt_hw_cpu_id_early
mov cpu_id ,r0
ldr lr ,= rt_hw_secondary_cpu_bsp_start
b enable_mmu_page_table_early
#endif
/* 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:
#ifdef RT_USING_SMP
stmfd sp!, {r0, r1}
cps #Mode_SVC
mov r0, sp /* svc_sp */
mov r1, lr /* svc_lr */
cps #Mode_IRQ
sub lr, #4
stmfd r0!, {r1, lr} /* svc_lr, svc_pc */
stmfd r0!, {r2 - r12}
ldmfd sp!, {r1, r2} /* original r0, r1 */
stmfd r0!, {r1 - r2}
mrs r1, spsr /* original mode */
stmfd r0!, {r1}
#ifdef RT_USING_SMART
stmfd r0, {r13, r14}^ /* usr_sp, usr_lr */
sub r0, #8
#endif
#ifdef RT_USING_FPU
/* fpu context */
vmrs r6, fpexc
tst r6, #(1<<30)
beq 1f
vstmdb r0!, {d0-d15}
vstmdb r0!, {d16-d31}
vmrs r5, fpscr
stmfd r0!, {r5}
1:
stmfd r0!, {r6}
#endif
/* now irq stack is clean */
/* r0 is task svc_sp */
/* backup r0 -> r8 */
mov r8, r0
cps #Mode_SVC
mov sp, r8
bl rt_interrupt_enter
bl rt_hw_trap_irq
bl rt_interrupt_leave
mov r0, r8
bl rt_scheduler_do_irq_switch
b rt_hw_context_switch_exit
#else
stmfd sp!, {r0-r12,lr}
bl rt_interrupt_enter
bl rt_hw_trap_irq
bl rt_interrupt_leave
/* 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
#ifdef RT_USING_SMART
ldmfd sp!, {r0-r12,lr}
cps #Mode_SVC
push {r0-r12}
mov r7, lr
cps #Mode_IRQ
mrs r4, spsr
sub r5, lr, #4
cps #Mode_SVC
and r6, r4, #0x1f
cmp r6, #0x10
bne 1f
msr spsr_csxf, r4
mov lr, r5
pop {r0-r12}
b arch_ret_to_user
1:
mov lr, r7
cps #Mode_IRQ
msr spsr_csxf, r4
mov lr, r5
cps #Mode_SVC
pop {r0-r12}
cps #Mode_IRQ
movs pc, lr
#else
ldmfd sp!, {r0-r12,lr}
subs pc, lr, #4
#endif
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 */
#ifdef RT_USING_SMART
stmfd sp, {r13, r14}^ /*push usr_sp, usr_lr */
sub sp, #8
#endif
#ifdef RT_USING_FPU
/* fpu context */
vmrs r6, fpexc
tst r6, #(1<<30)
beq 1f
vstmdb sp!, {d0-d15}
vstmdb sp!, {d16-d31}
vmrs r5, fpscr
stmfd sp!, {r5}
1:
stmfd sp!, {r6}
#endif
ldr r4, =rt_interrupt_from_thread
ldr r5, [r4]
str sp, [r5] /* store sp in preempted tasks's TCB */
ldr r6, =rt_interrupt_to_thread
ldr r6, [r6]
ldr sp, [r6] /* get new task's stack pointer */
#ifdef RT_USING_SMART
bl rt_thread_self
mov r4, r0
bl lwp_aspace_switch
mov r0, r4
bl lwp_user_setting_restore
#endif
#ifdef RT_USING_FPU
/* fpu context */
ldmfd sp!, {r6}
vmsr fpexc, r6
tst r6, #(1<<30)
beq 1f
ldmfd sp!, {r5}
vmsr fpscr, r5
vldmia sp!, {d16-d31}
vldmia sp!, {d0-d15}
1:
#endif
#ifdef RT_USING_SMART
ldmfd sp, {r13, r14}^ /*pop usr_sp, usr_lr */
add sp, #8
#endif
ldmfd sp!, {r4} /* pop new task's cpsr to spsr */
msr spsr_cxsf, r4
#ifdef RT_USING_SMART
and r4, #0x1f
cmp r4, #0x10
bne 1f
ldmfd sp!, {r0-r12,lr}
ldmfd sp!, {lr}
b arch_ret_to_user
1:
#endif
/* pop new task's r0-r12,lr & pc, copy spsr to cpsr */
ldmfd sp!, {r0-r12,lr,pc}^
#endif
.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
add sp, sp, #17 * 4
mrs r6, spsr /* Save CPSR */
str lr, [r0, #15*4] /* Push PC */
str r6, [r0, #16*4] /* Push CPSR */
and r1, r6, #0x1f
cmp r1, #0x10
cps #Mode_SYS
streq sp, [r0, #13*4] /* Save calling SP */
streq lr, [r0, #14*4] /* Save calling PC */
cps #Mode_SVC
strne sp, [r0, #13*4] /* Save calling SP */
strne lr, [r0, #14*4] /* Save calling PC */
.endm
.align 5
.weak 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
#ifdef RT_USING_FPU
cps #Mode_UND
sub sp, sp, #17 * 4
ldr lr, [sp, #15*4]
ldmia sp, {r0 - r12}
add sp, sp, #17 * 4
movs pc, lr
#endif
b .
.align 5
.globl vector_pabt
vector_pabt:
push_svc_reg
#ifdef RT_USING_SMART
/* cp Mode_ABT stack to SVC */
sub sp, sp, #17 * 4 /* Sizeof(struct rt_hw_exp_stack) */
mov lr, r0
ldmia lr, {r0 - r12}
stmia sp, {r0 - r12}
add r1, lr, #13 * 4
add r2, sp, #13 * 4
ldmia r1, {r4 - r7}
stmia r2, {r4 - r7}
mov r0, sp
bl rt_hw_trap_pabt
/* return to user */
ldr lr, [sp, #16*4] /* orign spsr */
msr spsr_cxsf, lr
ldr lr, [sp, #15*4] /* orign pc */
ldmia sp, {r0 - r12}
add sp, #17 * 4
b arch_ret_to_user
#else
bl rt_hw_trap_pabt
b .
#endif
.align 5
.globl vector_dabt
vector_dabt:
push_svc_reg
#ifdef RT_USING_SMART
/* cp Mode_ABT stack to SVC */
sub sp, sp, #17 * 4 /* Sizeof(struct rt_hw_exp_stack) */
mov lr, r0
ldmia lr, {r0 - r12}
stmia sp, {r0 - r12}
add r1, lr, #13 * 4
add r2, sp, #13 * 4
ldmia r1, {r4 - r7}
stmia r2, {r4 - r7}
mov r0, sp
bl rt_hw_trap_dabt
/* return to user */
ldr lr, [sp, #16*4] /* orign spsr */
msr spsr_cxsf, lr
ldr lr, [sp, #15*4] /* orign pc */
ldmia sp, {r0 - r12}
add sp, #17 * 4
b arch_ret_to_user
#else
bl rt_hw_trap_dabt
b .
#endif
.align 5
.globl vector_resv
vector_resv:
push_svc_reg
bl rt_hw_trap_resv
b .
.global rt_hw_clz
rt_hw_clz:
clz r0, r0
bx lr
#include "asm-generic.h"
START_POINT(_thread_start)
mov r10, lr
blx r1
blx r10
b . /* never here */
START_POINT_END(_thread_start)
.data
.align 14
init_mtbl:
.space (4*4096) /* The L1 translation table therefore contains 4096 32-bit (word-sized) entries. */
.global rt_hw_mmu_switch
rt_hw_mmu_switch:
orr r0, #0x18
mcr p15, 0, r0, c2, c0, 0 // ttbr0
//invalid tlb
mov r0, #0
mcr p15, 0, r0, c8, c7, 0
mcr p15, 0, r0, c7, c5, 0 //iciallu
mcr p15, 0, r0, c7, c5, 6 //bpiall
dsb
isb
mov pc, lr
.global rt_hw_set_process_id
rt_hw_set_process_id:
LSL r0, r0, #8
MCR p15, 0, r0, c13, c0, 1
mov pc, lr
.bss
.align 3 /* align to 2~3=8 */
.cpus_stack:
svc_stack_n:
#if defined(RT_USING_SMP) && (RT_CPUS_NR > 1)
.space ((RT_CPUS_NR - 1) * ARM_CPU_STACK_SIZE)
#endif
.space (ARM_CPU_STACK_SIZE)
svc_stack_top:
irq_stack_n:
#if defined(RT_USING_SMP) && (RT_CPUS_NR > 1)
.space ((RT_CPUS_NR - 1) * ARM_CPU_STACK_SIZE)
#endif
.space (ARM_CPU_STACK_SIZE)
irq_stack_top:
und_stack_n:
#if defined(RT_USING_SMP) && (RT_CPUS_NR > 1)
.space ((RT_CPUS_NR - 1) * ARM_CPU_STACK_SIZE)
#endif
.space (ARM_CPU_STACK_SIZE)
und_stack_top:
abt_stack_n:
#if defined(RT_USING_SMP) && (RT_CPUS_NR > 1)
.space ((RT_CPUS_NR - 1) * ARM_CPU_STACK_SIZE)
#endif
.space (ARM_CPU_STACK_SIZE)
abt_stack_top:

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-12-12 WangXiaoyao the first version
*/
#ifndef __TLB_H__
#define __TLB_H__
#include "mm_aspace.h"
#include <rtthread.h>
#include <stddef.h>
#include <stdint.h>
#define dsb(scope) __asm__ volatile("dsb " #scope : : : "memory")
#define isb() __asm__ volatile("isb" : : : "memory")
#define STORE_CP32(r, name...) "mcr " RT_STRINGIFY(CP32(%r, name)) ";"
#define WRITE_CP32(v, name...) do { \
register uint32_t _r = (v); \
asm volatile(STORE_CP32(0, name) : : "r" (_r)); \
} while (0)
static inline void rt_hw_tlb_invalidate_all(void)
{
asm volatile ("mcr p15, 0, r0, c8, c7, 0\ndsb\nisb" ::: "memory");
}
static inline void rt_hw_tlb_invalidate_all_local(void)
{
rt_hw_tlb_invalidate_all();
}
static inline void rt_hw_tlb_invalidate_aspace(rt_aspace_t aspace)
{
rt_hw_tlb_invalidate_all();
}
static inline void rt_hw_tlb_invalidate_range(rt_aspace_t aspace, void *start,
size_t size, size_t stride)
{
rt_hw_tlb_invalidate_all();
}
#endif /* __TLB_H__ */

View File

@@ -0,0 +1,390 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2013-07-20 Bernard first version
*/
#include <rthw.h>
#include <rtthread.h>
#include <board.h>
#include <backtrace.h>
#include "interrupt.h"
#include "mm_fault.h"
#include <rtdbg.h>
#ifdef RT_USING_FINSH
extern long list_thread(void);
#endif
#ifdef RT_USING_SMART
#include <lwp.h>
#include <lwp_arch.h>
#ifdef LWP_USING_CORE_DUMP
#include <lwp_core_dump.h>
#endif
void check_user_fault(struct rt_hw_exp_stack *regs, uint32_t pc_adj, char *info)
{
uint32_t mode = regs->cpsr;
if ((mode & 0x1f) == 0x10)
{
rt_kprintf("%s! pc = 0x%08x\n", info, regs->pc - pc_adj);
#ifdef LWP_USING_CORE_DUMP
lwp_core_dump(regs, pc_adj);
#endif
sys_exit_group(-1);
}
}
int check_data_abort(struct rt_hw_exp_stack *regs)
{
struct rt_lwp *lwp;
void *dfar = RT_NULL;
rt_base_t dfsr = RT_NULL;
__asm__ volatile("mrc p15, 0, %0, c6, c0, 0" : "=r"(dfar));
__asm__ volatile("mrc p15, 0, %0, c5, c0, 0" : "=r"(dfsr));
struct rt_aspace_fault_msg msg = {
.fault_op = MM_FAULT_OP_WRITE,
.fault_type = MM_FAULT_TYPE_PAGE_FAULT,
.fault_vaddr = dfar,
};
lwp = lwp_self();
if (lwp && rt_aspace_fault_try_fix(lwp->aspace, &msg))
{
regs->pc -= 8;
return 1;
}
return 0;
}
int check_prefetch_abort(struct rt_hw_exp_stack *regs)
{
struct rt_lwp *lwp;
void *ifar = RT_NULL;
rt_base_t ifsr = RT_NULL;
__asm__ volatile("mrc p15, 0, %0, c6, c0, 2" : "=r"(ifar));
__asm__ volatile("mrc p15, 0, %0, c5, c0, 1" : "=r"(ifsr));
struct rt_aspace_fault_msg msg = {
.fault_op = MM_FAULT_OP_READ,
.fault_type = MM_FAULT_TYPE_PAGE_FAULT,
.fault_vaddr = ifar,
};
lwp = lwp_self();
if (lwp && rt_aspace_fault_try_fix(lwp->aspace, &msg))
{
regs->pc -= 4;
return 1;
}
return 0;
}
#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);
#ifdef RT_USING_SMART
{
uint32_t v;
asm volatile ("MRC p15, 0, %0, c5, c0, 0":"=r"(v));
rt_kprintf("dfsr:0x%08x\n", v);
asm volatile ("MRC p15, 0, %0, c2, c0, 0":"=r"(v));
rt_kprintf("ttbr0:0x%08x\n", v);
asm volatile ("MRC p15, 0, %0, c6, c0, 0":"=r"(v));
rt_kprintf("dfar:0x%08x\n", v);
rt_kprintf("0x%08x -> 0x%08x\n", v, rt_kmem_v2p((void *)v));
}
#endif
}
/**
* 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
*/
#ifdef RT_USING_FPU
void set_fpexc(rt_uint32_t val);
#endif
void rt_hw_trap_undef(struct rt_hw_exp_stack *regs)
{
#ifdef RT_USING_FPU
{
uint32_t ins;
uint32_t addr;
if (regs->cpsr & (1 << 5))
{
/* thumb mode */
addr = regs->pc - 2;
ins = (uint32_t)*(uint16_t *)addr;
if ((ins & (3 << 11)) != 0)
{
/* 32 bit ins */
ins <<= 16;
ins += *(uint16_t *)(addr + 2);
}
}
else
{
addr = regs->pc - 4;
ins = *(uint32_t *)addr;
}
if ((ins & 0xe00) == 0xa00)
{
/* float ins */
set_fpexc(1U << 30);
regs->pc = addr;
return;
}
}
#endif
#ifdef RT_USING_SMART
check_user_fault(regs, 4, "User undefined instruction");
#endif
rt_unwind(regs, 4);
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)
{
#ifdef RT_USING_SMART
if (dbg_check_event(regs, 4))
{
return;
}
if (check_prefetch_abort(regs))
{
return;
}
check_user_fault(regs, 4, "User prefetch abort");
#endif
rt_unwind(regs, 4);
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)
{
#ifdef RT_USING_SMART
if (dbg_check_event(regs, 8))
{
return;
}
if (check_data_abort(regs))
{
return;
}
check_user_fault(regs, 8, "User data abort");
#endif
rt_unwind(regs, 8);
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();
}
void rt_hw_trap_irq(void)
{
#ifdef SOC_BCM283x
extern rt_uint8_t core_timer_flag;
void *param;
uint32_t irq;
rt_isr_handler_t isr_func;
extern struct rt_irq_desc isr_table[];
uint32_t value = 0;
value = IRQ_PEND_BASIC & 0x3ff;
if(core_timer_flag != 0)
{
uint32_t cpu_id = rt_hw_cpu_id();
uint32_t int_source = CORE_IRQSOURCE(cpu_id);
if (int_source & 0x0f)
{
if (int_source & 0x08)
{
isr_func = isr_table[IRQ_ARM_TIMER].handler;
#ifdef RT_USING_INTERRUPT_INFO
isr_table[IRQ_ARM_TIMER].counter++;
#endif
if (isr_func)
{
param = isr_table[IRQ_ARM_TIMER].param;
isr_func(IRQ_ARM_TIMER, param);
}
}
}
}
/* local interrupt*/
if (value)
{
if (value & (1 << 8))
{
value = IRQ_PEND1;
irq = __rt_ffs(value) - 1;
}
else if (value & (1 << 9))
{
value = IRQ_PEND2;
irq = __rt_ffs(value) + 31;
}
else
{
value &= 0x0f;
irq = __rt_ffs(value) + 63;
}
/* get interrupt service routine */
isr_func = isr_table[irq].handler;
#ifdef RT_USING_INTERRUPT_INFO
isr_table[irq].counter++;
#endif
if (isr_func)
{
/* Interrupt for myself. */
param = isr_table[irq].param;
/* turn to interrupt service routine */
isr_func(irq, param);
}
}
#else
void *param;
int ir, ir_real;
rt_isr_handler_t isr_func;
extern struct rt_irq_desc isr_table[];
ir = rt_hw_interrupt_get_irq();
ir_real = ir & 0x3ff;
if (ir == 1023)
{
/* Spurious interrupt */
return;
}
/* get interrupt service routine */
isr_func = isr_table[ir_real].handler;
#ifdef RT_USING_INTERRUPT_INFO
isr_table[ir_real].counter++;
#endif
if (isr_func)
{
/* Interrupt for myself. */
param = isr_table[ir_real].param;
/* turn to interrupt service routine */
isr_func(ir, param);
}
/* end of interrupt */
rt_hw_interrupt_ack(ir);
#endif
}
void rt_hw_trap_fiq(void)
{
void *param;
int ir;
rt_isr_handler_t isr_func;
extern struct rt_irq_desc isr_table[];
ir = rt_hw_interrupt_get_irq();
/* 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 */
rt_hw_interrupt_ack(ir);
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* 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:
#ifdef RT_USING_SMART
b _reset
#else
ldr pc, _vector_reset
#endif
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

View File

@@ -0,0 +1,23 @@
# RT-Thread building script for component
from building import *
Import('rtconfig')
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.cpp')
CPPPATH = [cwd]
if rtconfig.PLATFORM in ['armcc', 'armclang']:
src += Glob('*_rvds.S')
if rtconfig.PLATFORM in ['gcc']:
src += Glob('*_init.S')
src += Glob('*_gcc.S')
if rtconfig.PLATFORM in ['iccarm']:
src += Glob('*_iar.S')
group = DefineGroup('libcpu', src, depend = [''], CPPPATH = CPPPATH)
Return('group')

View File

@@ -0,0 +1,214 @@
/*
* Copyright (c) 2006-2022, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2010-01-25 Bernard first version
* 2012-06-01 aozima set pendsv priority to 0xFF.
* 2012-08-17 aozima fixed bug: store r8 - r11.
* 2013-02-20 aozima port to gcc.
* 2013-06-18 aozima add restore MSP feature.
* 2013-11-04 bright fixed hardfault bug for gcc.
*/
.cpu cortex-m0
.fpu softvfp
.syntax unified
.thumb
.text
.equ SCB_VTOR, 0xE000ED08 /* Vector Table Offset Register */
.equ NVIC_INT_CTRL, 0xE000ED04 /* interrupt control state register */
.equ NVIC_SHPR3, 0xE000ED20 /* system priority register (3) */
.equ NVIC_PENDSV_PRI, 0xFFFF0000 /* PendSV and SysTick priority value (lowest) */
.equ NVIC_PENDSVSET, 0x10000000 /* value to trigger PendSV exception */
/*
* rt_base_t rt_hw_interrupt_disable();
*/
.global rt_hw_interrupt_disable
.type rt_hw_interrupt_disable, %function
rt_hw_interrupt_disable:
MRS R0, PRIMASK
CPSID I
BX LR
/*
* void rt_hw_interrupt_enable(rt_base_t level);
*/
.global rt_hw_interrupt_enable
.type rt_hw_interrupt_enable, %function
rt_hw_interrupt_enable:
MSR PRIMASK, R0
BX LR
/*
* void rt_hw_context_switch(rt_uint32 from, rt_uint32 to);
* R0 --> from
* R1 --> to
*/
.global rt_hw_context_switch_interrupt
.type rt_hw_context_switch_interrupt, %function
.global rt_hw_context_switch
.type rt_hw_context_switch, %function
rt_hw_context_switch_interrupt:
rt_hw_context_switch:
/* set rt_thread_switch_interrupt_flag to 1 */
LDR R2, =rt_thread_switch_interrupt_flag
LDR R3, [R2]
CMP R3, #1
BEQ _reswitch
MOVS R3, #1
STR R3, [R2]
LDR R2, =rt_interrupt_from_thread /* set rt_interrupt_from_thread */
STR R0, [R2]
_reswitch:
LDR R2, =rt_interrupt_to_thread /* set rt_interrupt_to_thread */
STR R1, [R2]
LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
BX LR
/* R0 --> switch from thread stack
* R1 --> switch to thread stack
* psr, pc, LR, R12, R3, R2, R1, R0 are pushed into [from] stack
*/
.global PendSV_Handler
.type PendSV_Handler, %function
PendSV_Handler:
/* disable interrupt to protect context switch */
MRS R2, PRIMASK
CPSID I
/* get rt_thread_switch_interrupt_flag */
LDR R0, =rt_thread_switch_interrupt_flag
LDR R1, [R0]
CMP R1, #0x00
BEQ pendsv_exit /* pendsv already handled */
/* clear rt_thread_switch_interrupt_flag to 0 */
MOVS R1, #0
STR R1, [R0]
LDR R0, =rt_interrupt_from_thread
LDR R1, [R0]
CMP R1, #0x00
BEQ switch_to_thread /* skip register save at the first time */
MRS R1, PSP /* get from thread stack pointer */
SUBS R1, R1, #0x20 /* space for {R4 - R7} and {R8 - R11} */
LDR R0, [R0]
STR R1, [R0] /* update from thread stack pointer */
STMIA R1!, {R4 - R7} /* push thread {R4 - R7} register to thread stack */
MOV R4, R8 /* mov thread {R8 - R11} to {R4 - R7} */
MOV R5, R9
MOV R6, R10
MOV R7, R11
STMIA R1!, {R4 - R7} /* push thread {R8 - R11} high register to thread stack */
switch_to_thread:
LDR R1, =rt_interrupt_to_thread
LDR R1, [R1]
LDR R1, [R1] /* load thread stack pointer */
LDMIA R1!, {R4 - R7} /* pop thread {R4 - R7} register from thread stack */
PUSH {R4 - R7} /* push {R4 - R7} to MSP for copy {R8 - R11} */
LDMIA R1!, {R4 - R7} /* pop thread {R8 - R11} high register from thread stack to {R4 - R7} */
MOV R8, R4 /* mov {R4 - R7} to {R8 - R11} */
MOV R9, R5
MOV R10, R6
MOV R11, R7
POP {R4 - R7} /* pop {R4 - R7} from MSP */
MSR PSP, R1 /* update stack pointer */
pendsv_exit:
/* restore interrupt */
MSR PRIMASK, R2
MOVS R0, #0x04
RSBS R0, R0, #0x00
BX R0
/*
* void rt_hw_context_switch_to(rt_uint32 to);
* R0 --> to
*/
.global rt_hw_context_switch_to
.type rt_hw_context_switch_to, %function
rt_hw_context_switch_to:
LDR R1, =rt_interrupt_to_thread
STR R0, [R1]
/* set from thread to 0 */
LDR R1, =rt_interrupt_from_thread
MOVS R0, #0
STR R0, [R1]
/* set interrupt flag to 1 */
LDR R1, =rt_thread_switch_interrupt_flag
MOVS R0, #1
STR R0, [R1]
/* set the PendSV and SysTick exception priority */
LDR R0, =NVIC_SHPR3
LDR R1, =NVIC_PENDSV_PRI
LDR R2, [R0,#0x00] /* read */
ORRS R1, R1, R2 /* modify */
STR R1, [R0] /* write-back */
LDR R0, =NVIC_INT_CTRL /* trigger the PendSV exception (causes context switch) */
LDR R1, =NVIC_PENDSVSET
STR R1, [R0]
NOP
/* restore MSP */
LDR R0, =SCB_VTOR
LDR R0, [R0]
LDR R0, [R0]
NOP
MSR MSP, R0
/* enable interrupts at processor level */
CPSIE I
/* ensure PendSV exception taken place before subsequent operation */
DSB
ISB
/* never reach here! */
/* compatible with old version */
.global rt_hw_interrupt_thread_switch
.type rt_hw_interrupt_thread_switch, %function
rt_hw_interrupt_thread_switch:
BX LR
NOP
.global HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
/* get current context */
MRS R0, PSP /* get fault thread stack pointer */
PUSH {LR}
BL rt_hw_hard_fault_exception
POP {PC}
/*
* rt_uint32_t rt_hw_interrupt_check(void);
* R0 --> state
*/
.global rt_hw_interrupt_check
.type rt_hw_interrupt_check, %function
rt_hw_interrupt_check:
MRS R0, IPSR
BX LR

Some files were not shown because too many files have changed in this diff Show More