#ifndef _ARM_LOCORE_H_
#define _ARM_LOCORE_H_
#ifdef __arm__
#ifdef _KERNEL_OPT
#include "opt_cpuoptions.h"
#include "opt_cputypes.h"
#include "opt_arm_debug.h"
#endif
#include <sys/pcu.h>
#include <arm/cpuconf.h>
#include <arm/armreg.h>
#include <machine/frame.h>
#ifdef _LOCORE
#if defined(_ARM_ARCH_6)
#define IRQ_DISABLE(rTMP) cpsid i
#define IRQ_ENABLE(rTMP) cpsie i
#define INTERRUPT_DISABLE(rTMP) cpsid if
#define INTERRUPT_ENABLE(rTMP) cpsie if
#else
#define IRQ_DISABLE(rTMP) \
mrs rTMP, cpsr ; \
orr rTMP, rTMP, #(I32_bit) ; \
msr cpsr_c, rTMP
#define IRQ_ENABLE(rTMP) \
mrs rTMP, cpsr ; \
bic rTMP, rTMP, #(I32_bit) ; \
msr cpsr_c, rTMP
#define INTERRUPT_DISABLE(rTMP) \
mrs rTMP, cpsr ; \
orr rTMP, rTMP, #(I32_bit | F32_bit) ; \
msr cpsr_c, rTMP
#define INTERRUPT_ENABLE(rTMP) \
mrs rTMP, cpsr ; \
bic rTMP, rTMP, #(I32_bit | F32_bit) ; \
msr cpsr_c, rTMP
#endif
#if defined (TPIDRPRW_IS_CURCPU)
#define GET_CURCPU(rX) mrc p15, 0, rX, c13, c0, 4
#define GET_CURLWP(rX) GET_CURCPU(rX); ldr rX, [rX, #CI_CURLWP]
#define GET_CURX(rCPU, rLWP) GET_CURCPU(rCPU); ldr rLWP, [rCPU, #CI_CURLWP]
#elif defined (TPIDRPRW_IS_CURLWP)
#define GET_CURLWP(rX) mrc p15, 0, rX, c13, c0, 4
#if defined (MULTIPROCESSOR)
#define GET_CURCPU(rX) GET_CURLWP(rX); ldr rX, [rX, #L_CPU]
#define GET_CURX(rCPU, rLWP) GET_CURLWP(rLWP); ldr rCPU, [rLWP, #L_CPU]
#elif defined(_ARM_ARCH_7)
#define GET_CURCPU(rX) movw rX, #:lower16:cpu_info_store; movt rX, #:upper16:cpu_info_store
#define GET_CURX(rCPU, rLWP) GET_CURLWP(rLWP); GET_CURCPU(rCPU)
#else
#define GET_CURCPU(rX) ldr rX, =_C_LABEL(cpu_info_store)
#define GET_CURX(rCPU, rLWP) GET_CURLWP(rLWP); ldr rCPU, [rLWP, #L_CPU]
#endif
#elif !defined(MULTIPROCESSOR)
#define GET_CURCPU(rX) ldr rX, =_C_LABEL(cpu_info_store)
#define GET_CURLWP(rX) GET_CURCPU(rX); ldr rX, [rX, #CI_CURLWP]
#define GET_CURX(rCPU, rLWP) GET_CURCPU(rCPU); ldr rLWP, [rCPU, #CI_CURLWP]
#endif
#define GET_CURPCB(rX) GET_CURLWP(rX); ldr rX, [rX, #L_PCB]
#else
#include <arm/cpufunc.h>
#define IRQdisable __set_cpsr_c(I32_bit, I32_bit);
#define IRQenable __set_cpsr_c(I32_bit, 0);
#ifdef __NO_FIQ
#define VALID_PSR(psr) \
(((psr) & PSR_MODE) == PSR_USR32_MODE && ((psr) & I32_bit) == 0)
#else
#define VALID_PSR(psr) \
(((psr) & PSR_MODE) == PSR_USR32_MODE && ((psr) & IF32_bits) == 0)
#endif
#define TTBR_UPATTR (TTBR_S | TTBR_RGN_WBNWA | TTBR_C)
#define TTBR_MPATTR (TTBR_S | TTBR_RGN_WBNWA | TTBR_IRGN_WBNWA)
extern vaddr_t vector_page;
void arm32_vector_init(vaddr_t, int);
#define ARM_VEC_RESET (1 << 0)
#define ARM_VEC_UNDEFINED (1 << 1)
#define ARM_VEC_SWI (1 << 2)
#define ARM_VEC_PREFETCH_ABORT (1 << 3)
#define ARM_VEC_DATA_ABORT (1 << 4)
#define ARM_VEC_ADDRESS_EXCEPTION (1 << 5)
#define ARM_VEC_IRQ (1 << 6)
#define ARM_VEC_FIQ (1 << 7)
#define ARM_NVEC 8
#define ARM_VEC_ALL 0xffffffff
void cpu_attach(device_t, cpuid_t);
extern int cpu_do_powersave;
extern int cpu_printfataltraps;
extern int cpu_fpu_present;
extern int cpu_hwdiv_present;
extern int cpu_neon_present;
extern int cpu_simd_present;
extern int cpu_simdex_present;
extern int cpu_umull_present;
extern int cpu_synchprim_present;
extern int cpu_instruction_set_attributes[6];
extern int cpu_memory_model_features[4];
extern int cpu_processor_features[2];
extern int cpu_media_and_vfp_features[2];
extern bool arm_has_tlbiasid_p;
extern bool arm_has_mpext_p;
#if !defined(CPU_ARMV7)
#define CPU_IS_ARMV7_P() false
#elif defined(CPU_ARMV6) || defined(CPU_PRE_ARMV6)
extern bool cpu_armv7_p;
#define CPU_IS_ARMV7_P() (cpu_armv7_p)
#else
#define CPU_IS_ARMV7_P() true
#endif
#if !defined(CPU_ARMV6)
#define CPU_IS_ARMV6_P() false
#elif defined(CPU_ARMV7) || defined(CPU_PRE_ARMV6)
extern bool cpu_armv6_p;
#define CPU_IS_ARMV6_P() (cpu_armv6_p)
#else
#define CPU_IS_ARMV6_P() true
#endif
static inline uint32_t
read_insn(vaddr_t va, bool user_p)
{
uint32_t insn;
if (user_p) {
__asm __volatile("ldrt %0, [%1]" : "=&r"(insn) : "r"(va));
} else {
insn = *(const uint32_t *)va;
}
#ifdef _ARM_ARCH_BE8
insn = bswap32(insn);
#endif
return insn;
}
static inline uint32_t
read_thumb_insn(vaddr_t va, bool user_p)
{
va &= ~1;
uint32_t insn;
if (user_p) {
#if defined(__thumb__) && defined(_ARM_ARCH_T2)
__asm __volatile("ldrht %0, [%1, #0]" : "=&r"(insn) : "r"(va));
#elif defined(_ARM_ARCH_7)
__asm __volatile("ldrht %0, [%1], #0" : "=&r"(insn) : "r"(va));
#else
__asm __volatile("ldrt %0, [%1]" : "=&r"(insn) : "r"(va & ~3));
#ifdef __ARMEB__
insn = (uint16_t) (insn >> (((va ^ 2) & 2) << 3));
#else
insn = (uint16_t) (insn >> ((va & 2) << 3));
#endif
#endif
} else {
insn = *(const uint16_t *)va;
}
#ifdef _ARM_ARCH_BE8
insn = bswap16(insn);
#endif
return insn;
}
struct lwp;
void identify_arm_cpu(device_t, struct cpu_info *);
struct pcb;
void savectx(struct pcb *);
void userret(struct lwp *);
void bootsync(void);
int badaddr_read(void *, size_t, void *);
void swi_handler(trapframe_t *);
void vfp_detect(struct cpu_info *);
void vfp_attach(struct cpu_info *);
void vfp_discardcontext(lwp_t *, bool);
void vfp_savecontext(lwp_t *);
void vfp_kernel_acquire(void);
void vfp_kernel_release(void);
bool vfp_used_p(const lwp_t *);
extern const pcu_ops_t arm_vfp_ops;
#endif
#elif defined(__aarch64__)
#include <aarch64/locore.h>
#endif
#endif