?? arch.h
字號:
/* * (C) Finite State Machine Labs Inc. 1999 <business@fsmlabs.com> * * Released under the terms of GPL 2. * Open RTLinux makes use of a patented process described in * US Patent 5,995,745. Use of this process is governed * by the Open RTLinux Patent License which can be obtained from * www.fsmlabs.com/PATENT or by sending email to * licensequestions@fsmlabs.com */#include <linux/config.h>#include <linux/irq.h>#include <asm/irq.h>#include <asm/hw_irq.h>#include <asm/apic.h>#include <arch/constants.h>#include <rtl_core.h>extern struct irq_control_s irq_control;static struct irq_control_s pre_patch_control;#define RTL_NR_IRQS NR_IRQS/* interface to the hardware controller handlers */struct hw_interrupt_type *rtl_irq_desc[NR_IRQS];static struct hw_interrupt_type *save_linux_irq_desc[NR_IRQS];static inline int rtl_irq_controller_get_irq(struct pt_regs r){ return r.orig_eax & 0xff;}static inline void rtl_irq_controller_ack(unsigned int irq) { if(rtl_irq_desc[irq]) rtl_irq_desc[irq]->ack(irq);}static inline void rtl_irq_controller_enable(unsigned int irq){ if(rtl_irq_desc[irq]) rtl_irq_desc[irq]->enable(irq);}static inline void rtl_irq_controller_disable(unsigned int irq){ if(rtl_irq_desc[irq]) rtl_irq_desc[irq]->disable(irq);}void rtl_soft_cli(void);void rtl_soft_sti(void);void rtl_soft_save_flags(unsigned long *);void rtl_soft_restore_flags(unsigned long );void rtl_soft_local_irq_save(unsigned long *);void rtl_soft_local_irq_restore(unsigned long );/* dispatching rt and linux handlers */asmlinkage void (*xdo_IRQ)(struct pt_regs);struct rtl_global_handlers;static inline void dispatch_linux_irq(struct pt_regs *regs,unsigned int irq){ xdo_IRQ(*regs);}#ifdef CONFIG_X86_LOCAL_APICstatic void rtl_local_intercept(MACHDEPREGS );static inline void dispatch_rtl_local_handler(int pnd, struct pt_regs *r){ rtl_local[rtl_getcpuid()].rt_handlers[pnd](r);}struct { void (*smp_reschedule_interrupt)(void); void (*smp_invalidate_interrupt)(void); void (*smp_error_interrupt)(void); void (*smp_apic_timer_interrupt)(struct pt_regs *); void (*smp_call_function_interrupt)(void); void (*rtl_reschedule)(int cpu); void (*smp_spurious_interrupt)(void); }local_code;#endif#define FAKE_REGS { 0, 0, 0, 0, 0, 0, 0, __KERNEL_DS, 0, 0, (long)rtl_soft_sti, __KERNEL_CS, ARCH_DEFINED_ENABLE, 0, 0 } /* Called with soft disable set */inline void soft_dispatch_global(unsigned int irq){ struct pt_regs r = FAKE_REGS; DeclareAndInit(cpu_id); r.orig_eax = irq; L_CLEAR(l_ienable); xdo_IRQ(r);}#ifdef CONFIG_X86_LOCAL_APICvoid dispatch_local_linux_irq(struct pt_regs *r, int pnd){/* soft_dispatch_local(VECTOR_TO_LOCAL_PND(r->orig_eax)); */ soft_dispatch_local(r->orig_eax);/* __sti(); */}/* #define localdbg() do { if (test_bit(rtl_getcpuid(), &rtl_reserved_cpumask)) rtl_printf("l%x\n", vector); } while (0) */#define localdbg() do {;} while (0)void soft_dispatch_local(unsigned int vector){/* unsigned int vector = LOCAL_PND_TO_VECTOR(pnd); */ rtl_soft_cli();/* conpr("d"); conprn(vector); */ switch(vector){ /* IPI for rescheduling */ case RESCHEDULE_VECTOR: localdbg(); local_code.smp_reschedule_interrupt(); break; case INVALIDATE_TLB_VECTOR: /* IPI for invalidation */ localdbg(); local_code.smp_invalidate_interrupt(); break; case CALL_FUNCTION_VECTOR: localdbg(); local_code.smp_call_function_interrupt(); break; case SPURIOUS_APIC_VECTOR: localdbg(); local_code.smp_spurious_interrupt(); break; case ERROR_APIC_VECTOR: localdbg(); local_code.smp_error_interrupt(); break; case LOCAL_TIMER_VECTOR: { struct pt_regs r= FAKE_REGS; localdbg(); local_code.smp_apic_timer_interrupt(&r); } break; default: printk("RTL: bad local vector %x\n",vector); break; }}#endif/* Virtual functions for soft irq descriptor table */void rtl_virt_shutdown(unsigned int irq) { G_DISABLE(irq) ; rtl_irq_desc[irq]->shutdown(irq);}unsigned int rtl_virt_startup (unsigned int irq){ G_ENABLED(irq) ; return (rtl_irq_desc[irq]->startup(irq));}#if LINUX_VERSION_CODE < 0x020300void rtl_virt_handle (unsigned int irq, struct pt_regs * regs){ rtl_irq_desc[irq]->handle(irq, regs);}#endifstatic void rtl_virt_ack (unsigned int irq){ return;}#ifdef CONFIG_SMPstatic void rtl_virt_set_affinity(unsigned int irq, unsigned long mask){ if(rtl_irq_desc[irq] && rtl_irq_desc[irq]->set_affinity) { rtl_irq_desc[irq]->set_affinity(irq, mask); }}extern unsigned long irq_affinity [NR_IRQS];int rtl_irq_set_affinity (unsigned int irq, const unsigned long *mask, unsigned long *oldmask){ rtl_irqstate_t flags; if (irq >= RTL_RESCHEDULE_VECTOR - 0x20) { return -1; } if (!rtl_irq_desc[irq] || !rtl_irq_desc[irq]->set_affinity) { return -1; } if (oldmask) { *oldmask = irq_affinity[irq]; } if (! mask) { return 0; } if (!(*mask & cpu_online_map)) return -EINVAL; rtl_no_interrupts (flags); rtl_spin_lock (&rtl_global.hard_irq_controller_lock); irq_affinity[irq] = *mask; rtl_irq_desc[irq]->set_affinity(irq, *mask); rtl_spin_unlock (&rtl_global.hard_irq_controller_lock); rtl_restore_interrupts (flags); return 0;}#elsestatic void rtl_virt_set_affinity(unsigned int irq, unsigned long mask){;}int rtl_irq_set_affinity (unsigned int irq, const unsigned long *mask, unsigned long *oldmask){ return -1;}#endifvoid rtl_virt_enable(unsigned int);void rtl_virt_disable(unsigned int);struct hw_interrupt_type rtl_generic_type = {\ "RTLinux virtual irq", rtl_virt_startup, rtl_virt_shutdown, rtl_virt_enable, rtl_virt_disable, rtl_virt_ack, rtl_virt_enable, rtl_virt_set_affinity,#if LINUX_VERSION_CODE < 0x020300 rtl_virt_handle#endif};#ifdef CONFIG_SMP/* Michael's reschedule interrupt hack (use a global interrupt for it) */static void rtl_ack_apic(unsigned int irq) { ack_APIC_irq();}static void rtl_null_enable(unsigned int irq) {}struct hw_interrupt_type rtl_resched_irq_type = {\ "RTLinux reschedule irq", rtl_virt_startup, rtl_virt_shutdown, rtl_null_enable, rtl_virt_disable, rtl_ack_apic, rtl_virt_enable, rtl_virt_set_affinity,#if LINUX_VERSION_CODE < 0x020300 rtl_virt_handle /* nothing */#endif};#endifvoid (*local_ret_from_intr)(void);enum pfunctions {pf___start_rtlinux_patch,pf___stop_rtlinux_patch,pf_rtl_emulate_iret,pf_irq_desc,pf_do_IRQ,pf_ret_from_intr,pf_rtl_exception_intercept,#ifdef CONFIG_X86_LOCAL_APICpf_smp_spurious_interrupt,#define PF_LOCAL_START pf_smp_spurious_interruptpf_smp_error_interrupt,pf_smp_apic_timer_interrupt,#ifdef CONFIG_SMPpf_smp_reschedule_interrupt,pf_smp_invalidate_interrupt,pf_smp_call_function_interrupt,pf_rtl_reschedule,#define PF_LOCAL_END pf_smp_call_function_interrupt#else#define PF_LOCAL_END pf_smp_apic_timer_interrupt#endif /* CONFIG_SMP */#endif};/* #define DEBUG_RTLINUX 1 */#ifdef DEBUG_RTLINUX_PATCH_TABLEstatic void print_patch_table(void){ const struct func_table *p = &__start_rtlinux_funcs; struct patch_table *start_rtlinux_patch = p[0].address; struct patch_table *stop_rtlinux_patch = p[1].address; struct patch_table *pt;; printk("RTLinux table print start=%x stop=%x\n",p,&__stop_rtlinux_funcs); for(; p <= &__stop_rtlinux_funcs;p++) { printk("RTLinux function table %x => %x\n",p,p->address); } for(pt = start_rtlinux_patch; pt < stop_rtlinux_patch; pt++) printk("RTLinux patch table %x => %x %x\n",pt,pt->address,pt->magic); return;}#endif#define JUMP_SIZE 5#define MAX_JUMPS 20/* TODO patch_failure should do a recovery */#define patch_failure(x) {printk(x); return; }static char saved_jumps[MAX_JUMPS][JUMP_SIZE];static void save_jump(char *p, enum pfunctions pf){ int i; if(pf > MAX_JUMPS){ patch_failure("RTLinux FATAL ERROR; too many jumps\n"); }else for(i=0;i<5;i++)saved_jumps[pf][i] = p[i];}static void unpatch_jump(char *p, enum pfunctions pf){ int i; if(pf > MAX_JUMPS){ patch_failure("RTLinux FATAL ERROR; too many jumps in unpatch\n"); }else for(i=0;i<5;i++)p[i] = saved_jumps[pf][i];}static void patch_jump(char *code_to_patch,char *target){ int distance; distance = (int)target - ((int)code_to_patch +5) ; *code_to_patch++= 0xe9; /* jump */ *code_to_patch++ = ((char *)&distance)[0]; *code_to_patch++ = ((char *)&distance)[1]; *code_to_patch++ = ((char *)&distance)[2]; *code_to_patch = ((char *)&distance)[3];}/* IF THIS IS EVER CHANGED IN linux/arch/i386/rtlinux.h IT MUST BE CHANGED HERE TOO */#define ACK_MAGIC 0x12344321struct patch_table { char * address; unsigned long magic;};struct func_table { char * address;};extern const struct func_table *__start_rtlinux_funcs;extern const struct func_table *__stop_rtlinux_funcs;#ifdef CONFIG_X86_IO_APIC/* our version of level-triggered IO APIC irq controller */#if LINUX_VERSION_CODE >= 0x020300static struct hw_interrupt_type *linux_ioapic_level_irq_type_ptr = 0;static struct hw_interrupt_type rtl_ioapic_level_irq_type;void static rtl_mask_and_ack_level_ioapic_irq(unsigned int i){ linux_ioapic_level_irq_type_ptr->disable(i); /* mask */ linux_ioapic_level_irq_type_ptr->end(i); /* ack */}void static rtl_end_level_io_apic_irq(unsigned int i){ linux_ioapic_level_irq_type_ptr->enable(i); /* unmask */}#endif#endif /* CONFIG_X86_IO_APIC */#ifdef CONFIG_X86_LOCAL_APICvoid start_apic_ack(void);void end_apic_ack(void);static void rtl_local_irq_controller_ack(void){ asm __volatile__("start_apic_ack:\t\n"); ack_APIC_irq(); asm __volatile__("end_apic_ack:\t\n");}static inline char * match_ack(char *caller){ const struct func_table *pfunc = (struct func_table *)&__start_rtlinux_funcs; struct patch_table *p = (struct patch_table *)pfunc[pf___start_rtlinux_patch].address; char *closest=0; unsigned dis=0x7fffffff; /* distance *//* printk("searching %x\n", (unsigned) caller); */ for(; (ulong)p < (ulong)pfunc[pf___stop_rtlinux_patch].address;p++) { if (p->magic != ACK_MAGIC) { continue; } else {/* printk("%x, %x, %d\n", p->address, caller, dis); */ if ((unsigned) p->address >= (unsigned) caller && dis > ((unsigned)p->address - (unsigned)caller)) { dis = (ulong)p->address - (ulong)caller; closest = p->address; } } } return closest;}static void zap_ack_apic(char *apic_caller){ int i; int ack_len = (int) end_apic_ack - (int)start_apic_ack; char *call_point = match_ack(apic_caller); if(call_point){#ifdef DEBUG_RTLINUX printk("RTLinux debug zapping %x at %x\n",(unsigned int)apic_caller,(unsigned int)call_point);#endif for(i=0; i<ack_len; i++) call_point[i]= 0x90; }}static void unzap_ack_apic(char *apic_caller){ int i; int ack_len = (int) end_apic_ack - (int)start_apic_ack; char *call_point = match_ack(apic_caller); if(call_point){#ifdef DEBUG_RTLINUX printk("RTLinux debug unzapping %x at %x\n",(unsigned int)apic_caller,(unsigned int)call_point);#endif for(i=0; i<ack_len; i++) call_point[i]= ((char *)start_apic_ack)[i]; }}/* i8259.cBUILD_SMP_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -