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 + -
显示快捷键?