18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 38c2ecf20Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 48c2ecf20Sopenharmony_ci * for more details. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (C) 2001 - 2008 Tensilica Inc. 78c2ecf20Sopenharmony_ci * Copyright (C) 2015 Cadence Design Systems Inc. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#ifndef _XTENSA_PROCESSOR_H 118c2ecf20Sopenharmony_ci#define _XTENSA_PROCESSOR_H 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <asm/core.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/compiler.h> 168c2ecf20Sopenharmony_ci#include <linux/stringify.h> 178c2ecf20Sopenharmony_ci#include <asm/ptrace.h> 188c2ecf20Sopenharmony_ci#include <asm/types.h> 198c2ecf20Sopenharmony_ci#include <asm/regs.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* Assertions. */ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#if (XCHAL_HAVE_WINDOWED != 1) 248c2ecf20Sopenharmony_ci# error Linux requires the Xtensa Windowed Registers Option. 258c2ecf20Sopenharmony_ci#endif 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* Xtensa ABI requires stack alignment to be at least 16 */ 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define STACK_ALIGN (XCHAL_DATA_WIDTH > 16 ? XCHAL_DATA_WIDTH : 16) 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define ARCH_SLAB_MINALIGN STACK_ALIGN 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* 348c2ecf20Sopenharmony_ci * User space process size: 1 GB. 358c2ecf20Sopenharmony_ci * Windowed call ABI requires caller and callee to be located within the same 368c2ecf20Sopenharmony_ci * 1 GB region. The C compiler places trampoline code on the stack for sources 378c2ecf20Sopenharmony_ci * that take the address of a nested C function (a feature used by glibc), so 388c2ecf20Sopenharmony_ci * the 1 GB requirement applies to the stack as well. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU 428c2ecf20Sopenharmony_ci#define TASK_SIZE __XTENSA_UL_CONST(0x40000000) 438c2ecf20Sopenharmony_ci#else 448c2ecf20Sopenharmony_ci#define TASK_SIZE __XTENSA_UL_CONST(0xffffffff) 458c2ecf20Sopenharmony_ci#endif 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci#define STACK_TOP TASK_SIZE 488c2ecf20Sopenharmony_ci#define STACK_TOP_MAX STACK_TOP 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci/* 518c2ecf20Sopenharmony_ci * General exception cause assigned to fake NMI. Fake NMI needs to be handled 528c2ecf20Sopenharmony_ci * differently from other interrupts, but it uses common kernel entry/exit 538c2ecf20Sopenharmony_ci * code. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define EXCCAUSE_MAPPED_NMI 62 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * General exception cause assigned to debug exceptions. Debug exceptions go 608c2ecf20Sopenharmony_ci * to their own vector, rather than the general exception vectors (user, 618c2ecf20Sopenharmony_ci * kernel, double); and their specific causes are reported via DEBUGCAUSE 628c2ecf20Sopenharmony_ci * rather than EXCCAUSE. However it is sometimes convenient to redirect debug 638c2ecf20Sopenharmony_ci * exceptions to the general exception mechanism. To do this, an otherwise 648c2ecf20Sopenharmony_ci * unused EXCCAUSE value was assigned to debug exceptions for this purpose. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define EXCCAUSE_MAPPED_DEBUG 63 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci/* 708c2ecf20Sopenharmony_ci * We use DEPC also as a flag to distinguish between double and regular 718c2ecf20Sopenharmony_ci * exceptions. For performance reasons, DEPC might contain the value of 728c2ecf20Sopenharmony_ci * EXCCAUSE for regular exceptions, so we use this definition to mark a 738c2ecf20Sopenharmony_ci * valid double exception address. 748c2ecf20Sopenharmony_ci * (Note: We use it in bgeui, so it should be 64, 128, or 256) 758c2ecf20Sopenharmony_ci */ 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define VALID_DOUBLE_EXCEPTION_ADDRESS 64 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define XTENSA_INT_LEVEL(intno) _XTENSA_INT_LEVEL(intno) 808c2ecf20Sopenharmony_ci#define _XTENSA_INT_LEVEL(intno) XCHAL_INT##intno##_LEVEL 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#define XTENSA_INTLEVEL_MASK(level) _XTENSA_INTLEVEL_MASK(level) 838c2ecf20Sopenharmony_ci#define _XTENSA_INTLEVEL_MASK(level) (XCHAL_INTLEVEL##level##_MASK) 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define XTENSA_INTLEVEL_ANDBELOW_MASK(l) _XTENSA_INTLEVEL_ANDBELOW_MASK(l) 868c2ecf20Sopenharmony_ci#define _XTENSA_INTLEVEL_ANDBELOW_MASK(l) (XCHAL_INTLEVEL##l##_ANDBELOW_MASK) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci#define PROFILING_INTLEVEL XTENSA_INT_LEVEL(XCHAL_PROFILING_INTERRUPT) 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci/* LOCKLEVEL defines the interrupt level that masks all 918c2ecf20Sopenharmony_ci * general-purpose interrupts. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci#if defined(CONFIG_XTENSA_FAKE_NMI) && defined(XCHAL_PROFILING_INTERRUPT) 948c2ecf20Sopenharmony_ci#define LOCKLEVEL (PROFILING_INTLEVEL - 1) 958c2ecf20Sopenharmony_ci#else 968c2ecf20Sopenharmony_ci#define LOCKLEVEL XCHAL_EXCM_LEVEL 978c2ecf20Sopenharmony_ci#endif 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci#define TOPLEVEL XCHAL_EXCM_LEVEL 1008c2ecf20Sopenharmony_ci#define XTENSA_FAKE_NMI (LOCKLEVEL < TOPLEVEL) 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* WSBITS and WBBITS are the width of the WINDOWSTART and WINDOWBASE 1038c2ecf20Sopenharmony_ci * registers 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci#define WSBITS (XCHAL_NUM_AREGS / 4) /* width of WINDOWSTART in bits */ 1068c2ecf20Sopenharmony_ci#define WBBITS (XCHAL_NUM_AREGS_LOG2 - 2) /* width of WINDOWBASE in bits */ 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#ifndef __ASSEMBLY__ 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci/* Build a valid return address for the specified call winsize. 1118c2ecf20Sopenharmony_ci * winsize must be 1 (call4), 2 (call8), or 3 (call12) 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci#define MAKE_RA_FOR_CALL(ra,ws) (((ra) & 0x3fffffff) | (ws) << 30) 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* Convert return address to a valid pc 1168c2ecf20Sopenharmony_ci * Note: We assume that the stack pointer is in the same 1GB ranges as the ra 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_ci#define MAKE_PC_FROM_RA(ra,sp) (((ra) & 0x3fffffff) | ((sp) & 0xc0000000)) 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci/* Spill slot location for the register reg in the spill area under the stack 1218c2ecf20Sopenharmony_ci * pointer sp. reg must be in the range [0..4). 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ci#define SPILL_SLOT(sp, reg) (*(((unsigned long *)(sp)) - 4 + (reg))) 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci/* Spill slot location for the register reg in the spill area under the stack 1268c2ecf20Sopenharmony_ci * pointer sp for the call8. reg must be in the range [4..8). 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci#define SPILL_SLOT_CALL8(sp, reg) (*(((unsigned long *)(sp)) - 12 + (reg))) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* Spill slot location for the register reg in the spill area under the stack 1318c2ecf20Sopenharmony_ci * pointer sp for the call12. reg must be in the range [4..12). 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_ci#define SPILL_SLOT_CALL12(sp, reg) (*(((unsigned long *)(sp)) - 16 + (reg))) 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_citypedef struct { 1368c2ecf20Sopenharmony_ci unsigned long seg; 1378c2ecf20Sopenharmony_ci} mm_segment_t; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistruct thread_struct { 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* kernel's return address and stack pointer for context switching */ 1428c2ecf20Sopenharmony_ci unsigned long ra; /* kernel's a0: return address and window call size */ 1438c2ecf20Sopenharmony_ci unsigned long sp; /* kernel's a1: stack pointer */ 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci mm_segment_t current_ds; /* see uaccess.h for example uses */ 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* struct xtensa_cpuinfo info; */ 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci unsigned long bad_vaddr; /* last user fault */ 1508c2ecf20Sopenharmony_ci unsigned long bad_uaddr; /* last kernel fault accessing user space */ 1518c2ecf20Sopenharmony_ci unsigned long error_code; 1528c2ecf20Sopenharmony_ci#ifdef CONFIG_HAVE_HW_BREAKPOINT 1538c2ecf20Sopenharmony_ci struct perf_event *ptrace_bp[XCHAL_NUM_IBREAK]; 1548c2ecf20Sopenharmony_ci struct perf_event *ptrace_wp[XCHAL_NUM_DBREAK]; 1558c2ecf20Sopenharmony_ci#endif 1568c2ecf20Sopenharmony_ci /* Make structure 16 bytes aligned. */ 1578c2ecf20Sopenharmony_ci int align[0] __attribute__ ((aligned(16))); 1588c2ecf20Sopenharmony_ci}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* This decides where the kernel will search for a free chunk of vm 1618c2ecf20Sopenharmony_ci * space during mmap's. 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_ci#define TASK_UNMAPPED_BASE (TASK_SIZE / 2) 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci#define INIT_THREAD \ 1668c2ecf20Sopenharmony_ci{ \ 1678c2ecf20Sopenharmony_ci ra: 0, \ 1688c2ecf20Sopenharmony_ci sp: sizeof(init_stack) + (long) &init_stack, \ 1698c2ecf20Sopenharmony_ci current_ds: {0}, \ 1708c2ecf20Sopenharmony_ci /*info: {0}, */ \ 1718c2ecf20Sopenharmony_ci bad_vaddr: 0, \ 1728c2ecf20Sopenharmony_ci bad_uaddr: 0, \ 1738c2ecf20Sopenharmony_ci error_code: 0, \ 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* 1788c2ecf20Sopenharmony_ci * Do necessary setup to start up a newly executed thread. 1798c2ecf20Sopenharmony_ci * Note: When windowed ABI is used for userspace we set-up ps 1808c2ecf20Sopenharmony_ci * as if we did a call4 to the new pc. 1818c2ecf20Sopenharmony_ci * set_thread_state in signal.c depends on it. 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_USER_ABI_CALL0) 1848c2ecf20Sopenharmony_ci#define USER_PS_VALUE ((USER_RING << PS_RING_SHIFT) | \ 1858c2ecf20Sopenharmony_ci (1 << PS_UM_BIT) | \ 1868c2ecf20Sopenharmony_ci (1 << PS_EXCM_BIT)) 1878c2ecf20Sopenharmony_ci#else 1888c2ecf20Sopenharmony_ci#define USER_PS_VALUE (PS_WOE_MASK | \ 1898c2ecf20Sopenharmony_ci (1 << PS_CALLINC_SHIFT) | \ 1908c2ecf20Sopenharmony_ci (USER_RING << PS_RING_SHIFT) | \ 1918c2ecf20Sopenharmony_ci (1 << PS_UM_BIT) | \ 1928c2ecf20Sopenharmony_ci (1 << PS_EXCM_BIT)) 1938c2ecf20Sopenharmony_ci#endif 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* Clearing a0 terminates the backtrace. */ 1968c2ecf20Sopenharmony_ci#define start_thread(regs, new_pc, new_sp) \ 1978c2ecf20Sopenharmony_ci do { \ 1988c2ecf20Sopenharmony_ci unsigned long syscall = (regs)->syscall; \ 1998c2ecf20Sopenharmony_ci memset((regs), 0, sizeof(*(regs))); \ 2008c2ecf20Sopenharmony_ci (regs)->pc = (new_pc); \ 2018c2ecf20Sopenharmony_ci (regs)->ps = USER_PS_VALUE; \ 2028c2ecf20Sopenharmony_ci (regs)->areg[1] = (new_sp); \ 2038c2ecf20Sopenharmony_ci (regs)->areg[0] = 0; \ 2048c2ecf20Sopenharmony_ci (regs)->wmask = 1; \ 2058c2ecf20Sopenharmony_ci (regs)->depc = 0; \ 2068c2ecf20Sopenharmony_ci (regs)->windowbase = 0; \ 2078c2ecf20Sopenharmony_ci (regs)->windowstart = 1; \ 2088c2ecf20Sopenharmony_ci (regs)->syscall = syscall; \ 2098c2ecf20Sopenharmony_ci } while (0) 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* Forward declaration */ 2128c2ecf20Sopenharmony_cistruct task_struct; 2138c2ecf20Sopenharmony_cistruct mm_struct; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci/* Free all resources held by a thread. */ 2168c2ecf20Sopenharmony_ci#define release_thread(thread) do { } while(0) 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ciextern unsigned long get_wchan(struct task_struct *p); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci#define KSTK_EIP(tsk) (task_pt_regs(tsk)->pc) 2218c2ecf20Sopenharmony_ci#define KSTK_ESP(tsk) (task_pt_regs(tsk)->areg[1]) 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci#define cpu_relax() barrier() 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci/* Special register access. */ 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci#define xtensa_set_sr(x, sr) \ 2288c2ecf20Sopenharmony_ci ({ \ 2298c2ecf20Sopenharmony_ci __asm__ __volatile__ ("wsr %0, "__stringify(sr) :: \ 2308c2ecf20Sopenharmony_ci "a"((unsigned int)(x))); \ 2318c2ecf20Sopenharmony_ci }) 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci#define xtensa_get_sr(sr) \ 2348c2ecf20Sopenharmony_ci ({ \ 2358c2ecf20Sopenharmony_ci unsigned int v; \ 2368c2ecf20Sopenharmony_ci __asm__ __volatile__ ("rsr %0, "__stringify(sr) : "=a"(v)); \ 2378c2ecf20Sopenharmony_ci v; \ 2388c2ecf20Sopenharmony_ci }) 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci#if XCHAL_HAVE_EXTERN_REGS 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic inline void set_er(unsigned long value, unsigned long addr) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci asm volatile ("wer %0, %1" : : "a" (value), "a" (addr) : "memory"); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic inline unsigned long get_er(unsigned long addr) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci register unsigned long value; 2508c2ecf20Sopenharmony_ci asm volatile ("rer %0, %1" : "=a" (value) : "a" (addr) : "memory"); 2518c2ecf20Sopenharmony_ci return value; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci#endif /* XCHAL_HAVE_EXTERN_REGS */ 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci#endif /* __ASSEMBLY__ */ 2578c2ecf20Sopenharmony_ci#endif /* _XTENSA_PROCESSOR_H */ 258