/* linux/include/asm-e2k/traps.h, v 1.0 03/07/2001. * * Copyright (C) 2001 MCST * * Defenition of traps handling routines. */ #ifndef _E2K_TRAPS_H #define _E2K_TRAPS_H #include #include #include typedef void (*exc_function)(struct pt_regs *regs); extern const exc_function exc_tbl[]; extern const char *exc_tbl_name[]; #define S_SIG(regs, signo, trapno, code) \ do { \ int nr_TIRs; \ e2k_tir_hi_t tir_hi; \ struct trap_pt_regs *trap = (regs)->trap; \ void __user *addr; \ \ if (trap) { \ AW(tir_hi) = trap->TIR_hi; \ nr_TIRs = GET_NR_TIRS(AW(tir_hi)); \ addr = (void __user *) (trap->TIRs[nr_TIRs].TIR_lo.TIR_lo_ip); \ } else { \ addr = 0; \ } \ \ force_sig_fault(signo, code, addr, trapno); \ } while (0) extern int pf_on_page_boundary(unsigned long address, tc_cond_t cond); extern bool is_spurious_qp_store(bool store, unsigned long address, int fmt, tc_mask_t mask, unsigned long *pf_address); extern void parse_TIR_registers(struct pt_regs *regs, u64 exceptions); extern void do_aau_fault(int aa_field, struct pt_regs *regs); extern int handle_proc_stack_bounds(struct e2k_stacks *stacks, struct trap_pt_regs *trap); extern int handle_chain_stack_bounds(struct e2k_stacks *stacks, struct trap_pt_regs *trap); extern int do_page_fault(struct pt_regs *const regs, e2k_addr_t address, tc_cond_t condition, tc_mask_t mask, const int instr_page); #ifdef CONFIG_KVM_ASYNC_PF extern void do_pv_apf_wake(struct pt_regs *regs); #endif /* */ extern void do_trap_cellar(struct pt_regs *regs, int only_system_tc); extern irqreturn_t native_do_interrupt(struct pt_regs *regs); extern void do_nm_interrupt(struct pt_regs *regs); extern void native_instr_page_fault(struct pt_regs *regs, tc_fault_type_t ftype, const int async_instr); extern void do_trap_cellar(struct pt_regs *regs, int only_system_tc); extern int constrict_user_data_stack(struct pt_regs *regs, unsigned long incr); extern int expand_user_data_stack(struct pt_regs *regs, unsigned long incr); extern void do_notify_resume(struct pt_regs *regs); extern void coredump_in_future(void); enum getsp_action { GETSP_OP_FAIL = 1, GETSP_OP_SIGSEGV, GETSP_OP_INCREMENT, GETSP_OP_DECREMENT }; extern enum getsp_action parse_getsp_operation(const struct pt_regs *regs, int *incr, void __user **fault_addr); static inline unsigned int user_trap_init(void) { /* Enable system calls for user's processes. */ unsigned int linux_osem = 0; /* Enable deprecated generic ttable2 syscall entry. */ linux_osem = 1 << LINUX_SYSCALL_TRAPNUM_OLD; /* Enable ttable1 syscall entry - 32-bit syscalls only */ linux_osem |= 1 << LINUX_SYSCALL32_TRAPNUM; /* Enable ttable3 syscall entry - 64-bit syscalls only */ linux_osem |= 1 << LINUX_SYSCALL64_TRAPNUM; /* Enable fast syscalls entries. */ linux_osem |= 1 << LINUX_FAST_SYSCALL32_TRAPNUM; linux_osem |= 1 << LINUX_FAST_SYSCALL64_TRAPNUM; linux_osem |= 1 << LINUX_FAST_SYSCALL128_TRAPNUM; #ifdef CONFIG_PROTECTED_MODE linux_osem |= (1 << PMODE_SYSCALL_TRAPNUM); linux_osem |= (1 << PMODE_NEW_SYSCALL_TRAPNUM); #endif /* CONFIG_PROTECTED_MODE */ return linux_osem; } static inline unsigned int guest_trap_init(void) { /* Enable system calls for user's processes. */ unsigned int linux_osem = user_trap_init(); #ifdef CONFIG_KVM_HOST_MODE linux_osem |= HYPERCALLS_TRAPS_MASK; #endif return linux_osem; } static inline unsigned int user_hcall_init(void) { unsigned int linux_hcem = 0; linux_hcem = 1 << LINUX_HCALL_GENERIC_TRAPNUM; linux_hcem |= 1 << LINUX_HCALL_LIGHT_TRAPNUM; return linux_hcem; } extern char __hypercalls_begin[]; static inline void kernel_trap_mask_init(void) { WRITE_OSEM_REG(user_trap_init()); #ifdef CONFIG_KVM_HOST_MODE if (!paravirt_enabled()) { machine.rwd(E2K_REG_HCEM, user_hcall_init()); machine.rwd(E2K_REG_HCEB, (unsigned long) __hypercalls_begin); } #endif } static inline int native_host_apply_psp_delta_to_signal_stack(unsigned long base, unsigned long size, unsigned long start, unsigned long end, unsigned long delta) { /* native & host kernel cannot be paravirtualized guest */ return 0; } static inline int native_host_apply_pcsp_delta_to_signal_stack(unsigned long base, unsigned long size, unsigned long start, unsigned long end, unsigned long delta) { /* native & host kernel cannot be paravirtualized guest */ return 0; } /* * MMIO page fault cannot occur on native or host mode, * so ignore such traps */ static inline unsigned long native_mmio_page_fault(struct pt_regs *regs, trap_cellar_t *tcellar) { return 0; } #ifdef CONFIG_VIRTUALIZATION extern void native_sysrq_showstate_interrupt(struct pt_regs *regs); static inline void native_init_guest_system_handlers_table(void) { if (paravirt_enabled()) { /* It is native guest */ setup_APIC_vector_handler(SYSRQ_SHOWSTATE_EPIC_VECTOR, native_sysrq_showstate_interrupt, 1, "native_sysrq_showstate_interrupt"); } } # ifndef CONFIG_KVM # error "Undefined guest virtualization type" # endif /* CONFIG_KVM */ #else /* ! CONFIG_VIRTUALIZATION */ /* it is native host kernel without virtualization support */ static inline void native_init_guest_system_handlers_table(void) { /* Nothing to do */ } # define SET_RUNSTATE_IN_USER_TRAP() # define SET_RUNSTATE_OUT_USER_TRAP() # define SET_RUNSTATE_IN_KERNEL_TRAP(cur_runstate) # define SET_RUNSTATE_OUT_KERNEL_TRAP(cur_runstate) #endif /* CONFIG_VIRTUALIZATION */ #if defined(CONFIG_KVM_GUEST_KERNEL) /* It is pure guest kernel (not paravirtualized) */ #include #elif defined(CONFIG_PARAVIRT_GUEST) /* It is paravirtualized host and guest kernel */ #include #else /* ! CONFIG_PARAVIRT_GUEST && ! CONFIG_KVM_GUEST_KERNEL */ /* it is native kernel without any virtualization */ /* or it is native host kernel with virtualization support */ #define TIR0_clear_false_exceptions(TIR_hi, nr_TIRs) \ native_TIR0_clear_false_exceptions(TIR_hi, nr_TIRs) static inline void handle_interrupt(struct pt_regs *regs) { native_do_interrupt(regs); } extern int apply_psp_delta_to_signal_stack(unsigned long base, unsigned long size, unsigned long start, unsigned long end, unsigned long delta); extern int apply_pcsp_delta_to_signal_stack(unsigned long base, unsigned long size, unsigned long start, unsigned long end, unsigned long delta); static inline int host_apply_psp_delta_to_signal_stack(unsigned long base, unsigned long size, unsigned long start, unsigned long end, unsigned long delta) { return native_host_apply_psp_delta_to_signal_stack(base, size, start, end, delta); } static inline int host_apply_pcsp_delta_to_signal_stack(unsigned long base, unsigned long size, unsigned long start, unsigned long end, unsigned long delta) { return native_host_apply_pcsp_delta_to_signal_stack(base, size, start, end, delta); } static inline unsigned long mmio_page_fault(struct pt_regs *regs, trap_cellar_t *tcellar) { return native_mmio_page_fault(regs, tcellar); } static inline void init_guest_system_handlers_table(void) { native_init_guest_system_handlers_table(); } #endif /* ! CONFIG_PARAVIRT_GUEST && ! CONFIG_KVM_GUEST_KERNEL */ #endif /* _E2K_TRAPS_H */