arch.c
来自「rtlinux3.0 的源代码」· C语言 代码 · 共 255 行
C
255 行
/* * (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 <asm/uaccess.h>#include <asm/system.h>#include <linux/irq.h>#include <asm/irq.h>#include "arch.h"#include <rtl_core.h>#include <rtl_sync.h>struct int_control_struct rtl_hard_int_control;irq_desc_t rtl_hard_irq_desc[NR_IRQS];unsigned long hard_timer_interrupt, hard_do_IRQ, hard_do_IRQ2, hard_do_IRQ3;int (*hard_get_irq)(struct pt_regs *);void (*hard_post_irq)(struct pt_regs *, int);int bogus_get_irq(struct pt_regs *);unsigned int (*timer_handler)(struct pt_regs *r);extern ulong ret_to_user_hook;extern void flush_icache_range(ulong, ulong);void rtl_local_intercept(struct pt_regs *regs);int rtl_irq_set_affinity (unsigned int irq, const unsigned long *mask, unsigned long *oldmask){ return -1;}void rtl_hard_pic_end(unsigned int irq_nr){ if ( rtl_hard_irq_desc[irq_nr].handler && rtl_hard_irq_desc[irq_nr].handler->end ) rtl_hard_irq_desc[irq_nr].handler->end(irq_nr);}hw_irq_controller rtl_fake_pic ={ " RTLinux PIC ", NULL, NULL, rtl_virt_enable, rtl_virt_disable, NULL, /*rtl_hard_pic_end*/0 };void ppc_rtl_soft_restore_flags(unsigned long x){ rtl_soft_restore_flags(x&MSR_EE);}void rtl_set_lost(unsigned long irq){ rtl_global_pend_irq(irq);}struct { atomic_t waiting; atomic_t done;} sync_data = {{0},{0}};void sync_takeover(void *unused){ int i; __cli(); atomic_inc(&sync_data.waiting); i = 0; while ( !atomic_read(&sync_data.done) && (i < 1000000000) ) { i++; if (i == 1000000000) printk("timed out on sync_data.done\n"); } rtl_hard_sti();}void sync_giveup(void *unused){ int i; rtl_hard_cli(); atomic_inc(&sync_data.waiting); i = 0; while ( !atomic_read(&sync_data.done) && (i < 1000000000) ) { i++; if (i == 1000000000) printk("timed out on sync_data.done\n"); } __sti();}/* * Architecture specific function to take over the handling of interrupts. * -- Cort */int arch_takeover(void){ int i; struct task_struct *p; void rtl_soft_sti_no_emulation(void); if ( timer_interrupt_intercept != (unsigned long)timer_interrupt ) { /*printk("RTL: Timer interrupt already being intercepted!\n");*/ return -1; } { unsigned long block[7] = { 0x7fe802a6, /* mflr 31 */ 0x3fc0dead, /* lis 0xdeadbeef@h */ 0x63debeef, /* ori r30,r30,0xdeadbeef@l */ 0x7fc803a6, /* mtlr r30 */ 0x4e800021, /* blrl */ 0x7fe803a6, /* mtlr r31 */ 0x4e800020 /* blr */ }; block[1] = (block[1]&0xffff0000) | (((ulong)rtl_soft_sti>>16)&0xffff); block[2] = (block[2]&0xffff0000) | ((ulong)rtl_soft_sti&0xffff); memcpy( (ulong *)KERNELBASE, &block, sizeof(ulong)*7 ); flush_icache_range(KERNELBASE, KERNELBASE+(sizeof(ulong)*7)); } ret_to_user_hook = 0x48000000 | 1 | (((KERNELBASE+0x0) - (ulong)&ret_to_user_hook)&0x03fffffc); flush_icache_range((ulong)&ret_to_user_hook, (ulong)&ret_to_user_hook); __cli(); /* copy the current (hard) versions from the kernel... */ rtl_hard_int_control = int_control; memcpy(rtl_hard_irq_desc, irq_desc, sizeof(irq_desc_t)*NR_IRQS); hard_timer_interrupt = timer_interrupt_intercept; hard_do_IRQ = do_IRQ_intercept; hard_get_irq = ppc_md.get_irq; hard_post_irq = ppc_md.post_irq; /* ...and replace them with our soft versions */ int_control.int_cli = rtl_soft_cli; int_control.int_sti = rtl_soft_sti; int_control.int_save_flags = rtl_soft_save_flags; int_control.int_restore_flags = ppc_rtl_soft_restore_flags; int_control.int_set_lost = rtl_set_lost; atomic_set(&ppc_n_lost_interrupts,0); for ( i = 0 ; i < NR_MASK_WORDS; i++ ) ppc_lost_interrupts[i] = 0; do_IRQ_intercept = (unsigned long)rtl_intercept; timer_interrupt_intercept = (unsigned long)rtl_local_intercept; /* * This should never be called since it's only used in the * linux version of do_IRQ() but just in case... * -- Cort */ ppc_md.get_irq = bogus_get_irq; ppc_md.post_irq = NULL; /* replace all the interrupt controller pointers with our fake one */ for ( i = 0 ; i < NR_IRQS; i++ ) if ( irq_desc[i].handler ) irq_desc[i].handler = &rtl_fake_pic; /* * Now we need to correct for any tasks that may have * MSR_EE cleared (interrupts disabled) in their task * struct so they don't disable when switching back to * them. * -- Cort */ /* have to do init_task separately */ ((struct pt_regs *)(init_task.thread.ksp+STACK_FRAME_OVERHEAD))->msr |= MSR_EE; for_each_task(p) { ((struct pt_regs *)(p->thread.ksp+STACK_FRAME_OVERHEAD))->msr |= MSR_EE; if ( p->thread.regs ) p->thread.regs->msr |= MSR_EE; } /* * This hard sti matches the above cli() since the cli() * was hard (RTLinux wasn't loaded yet). * -- Cort */ rtl_hard_sti(); __sti(); return 0;}void arch_giveup(void){ rtl_hard_cli(); int_control = rtl_hard_int_control; timer_interrupt_intercept = hard_timer_interrupt; do_IRQ_intercept = hard_do_IRQ; ppc_md.get_irq = hard_get_irq; ppc_md.post_irq = hard_post_irq; /* clear out our call to to the rtl_soft_sti trampoline code in the ret from int path */ ret_to_user_hook = 0x60000000; /* nop */ flush_icache_range((ulong)&ret_to_user_hook, (ulong)&ret_to_user_hook); memcpy(irq_desc, rtl_hard_irq_desc, sizeof(irq_desc_t)*NR_IRQS); /* * This is safe since we have turned off RTLinux and * the RTLinux __sti() will behave just like the normal * linux __sti(). -- Cort */ __sti();}int bogus_get_irq(struct pt_regs *regs){ printk("BOGUS_GET_IRQ! from %p\n", __builtin_return_address(0)); *(unsigned long *)(0) = 1; return -1;}void dispatch_rtl_local_irq(int irq){ struct pt_regs r; if ( !(unsigned long)timer_handler ) printk("No timer handler in dispatch_rtl_local_irq!\n"); else timer_handler(&r);}int rtl_free_local_irq(int i, unsigned int cpu){ if ( (unsigned long)timer_handler ) { (unsigned long)timer_handler = 0; clear_bit(0,&rtl_local[smp_processor_id()].rtirq); } else return -EINVAL; return 0;}int rtl_request_local_irq(int i, unsigned int (*handler)(struct pt_regs *r), unsigned int cpu){ if ( !(unsigned long)timer_handler ) { timer_handler = handler; set_bit(0,&rtl_local[smp_processor_id()].rtirq); return 0; } else return -EINVAL;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?