Пример #1
0
static void trap_init(void)
{
	extern char except_vec3_generic;
	int i;

	unsigned long ebase;

	ebase = CKSEG1;

	/*
	 * Copy the generic exception handlers to their final destination.
	 * This will be overriden later as suitable for a particular
	 * configuration.
	 */
	memcpy((void *)(ebase + 0x180), &except_vec3_generic, 0x80);

	/*
	 * Setup default vectors
	 */
	for (i = 0; i <= 31; i++) {
		set_except_vector(i, &handle_reserved);
	}

	if (!cpu_has_4kex)
		memcpy((void *)(ebase + 0x080), &except_vec3_generic, 0x80);

	/* FIXME: handle tlb */
	memcpy((void *)(ebase), &except_vec3_generic, 0x80);

	/* unset BOOT EXCEPTION VECTOR bit */
	write_c0_status(read_c0_status() & ~ST0_BEV);
}
Пример #2
0
static void
tx4927_irq_cp0_modify(unsigned cp0_reg, unsigned clr_bits, unsigned set_bits)
{
	unsigned long val = 0;

	switch (cp0_reg) {
	case CCP0_STATUS:
		val = read_c0_status();
		break;

	case CCP0_CAUSE:
		val = read_c0_cause();
		break;

	}

	val &= (~clr_bits);
	val |= (set_bits);

	switch (cp0_reg) {
	case CCP0_STATUS:{
			write_c0_status(val);
			break;
		}
	case CCP0_CAUSE:{
			write_c0_cause(val);
			break;
		}
	}

	return;
}
Пример #3
0
void tlb_init(void)
{
	unsigned int config = read_c0_config();
	unsigned long status;

	probe_tlb(config);

	status = read_c0_status();
	status &= ~(ST0_UPS | ST0_KPS);
#ifdef CONFIG_PAGE_SIZE_4KB
	status |= (TFP_PAGESIZE_4K << 32) | (TFP_PAGESIZE_4K << 36);
#elif defined(CONFIG_PAGE_SIZE_8KB)
	status |= (TFP_PAGESIZE_8K << 32) | (TFP_PAGESIZE_8K << 36);
#elif defined(CONFIG_PAGE_SIZE_16KB)
	status |= (TFP_PAGESIZE_16K << 32) | (TFP_PAGESIZE_16K << 36);
#elif defined(CONFIG_PAGE_SIZE_64KB)
	status |= (TFP_PAGESIZE_64K << 32) | (TFP_PAGESIZE_64K << 36);
#endif
	write_c0_status(status);

	write_c0_wired(0);

	local_flush_tlb_all();

	build_tlb_refill_handler();
}
Пример #4
0
void __init arch_init_irq(void)
{
	unsigned int irq;

	/*                                  */
	mips_cpu_irq_init();

	/*                                 */
	for (irq = PNX833X_PIC_IRQ_BASE; irq < (PNX833X_PIC_IRQ_BASE + PNX833X_PIC_NUM_IRQ); irq++) {
		pnx833x_hard_disable_pic_irq(irq);
		irq_set_chip_and_handler(irq, &pnx833x_pic_irq_type,
					 handle_simple_irq);
	}

	for (irq = PNX833X_GPIO_IRQ_BASE; irq < (PNX833X_GPIO_IRQ_BASE + PNX833X_GPIO_NUM_IRQ); irq++)
		irq_set_chip_and_handler(irq, &pnx833x_gpio_irq_type,
					 handle_simple_irq);

	/*                                        */
	PNX833X_PIC_INT_PRIORITY = 0;

	/*                            */
	pnx833x_startup_pic_irq(PNX833X_PIC_GPIO_INT);

	/*                          */
	if (cpu_has_vint)
		set_vi_handler(4, pic_dispatch);

	write_c0_status(read_c0_status() | IE_IRQ2);
}
Пример #5
0
void __init tlb_init(void)
{
	unsigned int config = read_c0_config();
	unsigned long status;

	probe_tlb(config);

	status = read_c0_status();
	status &= ~(ST0_UPS | ST0_KPS);
#ifdef CONFIG_PAGE_SIZE_4KB
	status |= (TFP_PAGESIZE_4K << 32) | (TFP_PAGESIZE_4K << 36);
#elif defined(CONFIG_PAGE_SIZE_8KB)
	status |= (TFP_PAGESIZE_8K << 32) | (TFP_PAGESIZE_8K << 36);
#elif defined(CONFIG_PAGE_SIZE_16KB)
	status |= (TFP_PAGESIZE_16K << 32) | (TFP_PAGESIZE_16K << 36);
#elif defined(CONFIG_PAGE_SIZE_64KB)
	status |= (TFP_PAGESIZE_64K << 32) | (TFP_PAGESIZE_64K << 36);
#endif
	write_c0_status(status);

	write_c0_wired(0);

	local_flush_tlb_all();

	memcpy((void *)(CKSEG0 + 0x00), &except_vec0_generic, 0x80);
	memcpy((void *)(CKSEG0 + 0x80), except_vec1_r8k, 0x80);
	flush_icache_range(CKSEG0 + 0x80, CKSEG0 + 0x100);
}
void __init arch_init_irq(void)
{
	unsigned int irq;

	/* setup standard internal cpu irqs */
	mips_cpu_irq_init();

	/* Set IRQ information in irq_desc */
	for (irq = PNX833X_PIC_IRQ_BASE; irq < (PNX833X_PIC_IRQ_BASE + PNX833X_PIC_NUM_IRQ); irq++) {
		pnx833x_hard_disable_pic_irq(irq);
		irq_set_chip_and_handler(irq, &pnx833x_pic_irq_type,
					 handle_simple_irq);
	}

	for (irq = PNX833X_GPIO_IRQ_BASE; irq < (PNX833X_GPIO_IRQ_BASE + PNX833X_GPIO_NUM_IRQ); irq++)
		irq_set_chip_and_handler(irq, &pnx833x_gpio_irq_type,
					 handle_simple_irq);

	/* Set PIC priority limiter register to 0 */
	PNX833X_PIC_INT_PRIORITY = 0;

	/* Setup GPIO IRQ dispatching */
	pnx833x_startup_pic_irq(PNX833X_PIC_GPIO_INT);

	/* Enable PIC IRQs (HWIRQ2) */
	if (cpu_has_vint)
		set_vi_handler(4, pic_dispatch);

	write_c0_status(read_c0_status() | IE_IRQ2);
}
Пример #7
0
/*
 * hwint 1 deals with EISA and SCSI interrupts,
 *
 * The EISA_INT bit in CSITPEND is high active, all others are low active.
 */
static void pcimt_hwint1(void)
{
	u8 pend = *(volatile char *)PCIMT_CSITPEND;
	unsigned long flags;

	if (pend & IT_EISA) {
		int irq;
		/*
		 * Note: ASIC PCI's builtin interrupt acknowledge feature is
		 * broken.  Using it may result in loss of some or all i8259
		 * interrupts, so don't use PCIMT_INT_ACKNOWLEDGE ...
		 */
		irq = i8259_irq();
		if (unlikely(irq < 0))
			return;

		do_IRQ(irq);
	}

	if (!(pend & IT_SCSI)) {
		flags = read_c0_status();
		clear_c0_status(ST0_IM);
		do_IRQ(PCIMT_IRQ_SCSI);
		write_c0_status(flags);
	}
}
Пример #8
0
void __init arch_init_irq(void)
{
	unsigned int i;

	set_irq_priority();

	/* clear interrupt counter for VPE0 and VPE1 */
	if (isRT6855A)
		tc_outl(CR_INTC_ITR, (1 << 18) | (1 << 10));

	/* Disable all hardware interrupts */
	clear_c0_status(ST0_IM);
	clear_c0_cause(CAUSEF_IP);

	/* Initialize IRQ action handlers */
	for (i = 0; i < NR_IRQS; i++) {
#ifdef CONFIG_MIPS_TC3262
		/*
	 	 * Only MT is using the software interrupts currently, so we just
	 	 * leave them uninitialized for other processors.
	 	 */
		if (cpu_has_mipsmt) {
			if ((i == SI_SWINT1_INT0) || (i == SI_SWINT1_INT1) ||
				(i == SI_SWINT_INT0) || (i == SI_SWINT_INT1)) { 
				set_irq_chip(i, &mips_mt_cpu_irq_controller);
				continue;
			}
		}

		if ((i == SI_TIMER_INT) || (i == SI_TIMER1_INT))
			set_irq_chip_and_handler(i, &tc3162_irq_chip,
					 handle_percpu_irq);
		else
			set_irq_chip_and_handler(i, &tc3162_irq_chip,
					 handle_level_irq);
#else
		set_irq_chip_and_handler(i, &tc3162_irq_chip,
					 handle_level_irq);
#endif
	}

#ifdef CONFIG_MIPS_TC3262
	if (cpu_has_veic || cpu_has_vint) {
		write_c0_status((read_c0_status() & ~ST0_IM ) |
			                (STATUSF_IP0 | STATUSF_IP1)); 

		/* register irq dispatch functions */
		for (i = 0; i < NR_IRQS; i++)
			set_vi_handler(i, irq_dispatch_tab[i]);
	} else {
		change_c0_status(ST0_IM, ALLINTS);
	}
#else
	/* Enable all interrupts */
	change_c0_status(ST0_IM, ALLINTS);
#endif
#ifdef CONFIG_MIPS_MT_SMP
	vsmp_int_init();
#endif
}
Пример #9
0
static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
{
	unsigned long status = read_c0_status();

	status &= ~((clr_mask & 0xFF) << 8);
	status |= (set_mask & 0xFF) << 8;

	write_c0_status(status);
}
Пример #10
0
void restore_processor_state(void)
{
	write_c0_status(saved_status);

	if (is_fpu_owner())
		restore_fp(current);
	if (cpu_has_dsp)
		restore_dsp(current);
}
Пример #11
0
/*
 * Get the FPU Implementation/Revision.
 */
static inline unsigned long cpu_get_fpu_id(void)
{
	unsigned long tmp, fpu_id;

	tmp = read_c0_status();
	__enable_fpu();
	fpu_id = read_32bit_cp1_register(CP1_REVISION);
	write_c0_status(tmp);
	return fpu_id;
}
void __init plat_time_init(void)
{
    /* JU: TBD: there was some special SMP handling added here in original kernel */
    mips_hpt_frequency = calculateCpuSpeed() / 2;
#if defined(CONFIG_BCM_PWRMNGT) || defined(CONFIG_BCM_PWRMNGT_MODULE)
    BcmPwrMngtInitC0Speed();
#else
    // Enable cp0 counter/compare interrupt only when not using power management
    write_c0_status(IE_IRQ5 | read_c0_status());
#endif
}
Пример #13
0
void mips_cpu_timer_enable(void)
{
	uint32_t sr = read_c0_status();
	sr |= ((0x1UL << 7) << 8);
	write_c0_status(sr);

	uint32_t cause = read_c0_cause();
	cause &= ~(0x1UL << 27);
	write_c0_cause(cause);
	write_c0_compare(read_c0_count() + COUNTER_TICK_COUNT);
}
Пример #14
0
void exception_init(void)
{
    write_c0_status(0x10000400);

    memcpy((void *)(A_K0BASE        ), except_common_entry, 0x20);
    memcpy((void *)(A_K0BASE + 0x180), except_common_entry, 0x20);
    memcpy((void *)(A_K0BASE + 0x200), except_common_entry, 0x20);

    __dcache_writeback_all();
    __icache_invalidate_all();
}
Пример #15
0
static void paravirt_init_secondary(void)
{
	unsigned int sr;

	sr = set_c0_status(ST0_BEV);
	write_c0_ebase((u32)ebase);

	sr |= STATUSF_IP2; /* Interrupt controller on IP2 */
	write_c0_status(sr);

	irq_cpu_online();
}
Пример #16
0
/**
 * Disable access to Octeon's COP2 crypto hardware in the kernel.
 * This must be called after an octeon_crypto_enable() before any
 * context switch or return to userspace.
 *
 * @param state  COP2 state to restore
 * @param flags  Return value from octeon_crypto_enable()
 */
void octeon_crypto_disable(struct octeon_cop2_state *state,
			   unsigned long crypto_flags)
{
	unsigned long flags;

	local_irq_save(flags);
	if (crypto_flags & ST0_CU2)
		octeon_cop2_restore(state);
	else
		write_c0_status(read_c0_status() & ~ST0_CU2);
	local_irq_restore(flags);
}
Пример #17
0
static int cnmips_cu2_call(struct notifier_block *nfb, unsigned long action,
	void *data)
{
	unsigned long flags;
	unsigned int status;

	switch (action) {
	case CU2_EXCEPTION:
		prefetch(&current->thread.cp2);
		local_irq_save(flags);
		KSTK_STATUS(current) |= ST0_CU2;
		status = read_c0_status();
		write_c0_status(status | ST0_CU2);
		octeon_cop2_restore(&(current->thread.cp2));
		write_c0_status(status & ~ST0_CU2);
		local_irq_restore(flags);

		return NOTIFY_BAD;	/* Don't call default notifier */
	}

	return NOTIFY_OK;		/* Let default notifier send signals */
}
Пример #18
0
/**
 * After we've done initial boot, this function is called to allow the
 * board code to clean up state, if needed
 */
static void octeon_init_secondary(void)
{
	unsigned int sr;

	sr = set_c0_status(ST0_BEV);
	write_c0_ebase((u32)ebase);
	write_c0_status(sr);

	octeon_check_cpu_bist();
	octeon_init_cvmcount();

	octeon_irq_setup_secondary();
}
Пример #19
0
void __init arch_init_irq(void)
{
	int i;
	//extern irq_desc_t irq_desc[];

	/* init CPU irqs */
	mips_cpu_irq_init();

	/* init sys irqs */
	sys_irq_base = M36_SYS_IRQ_BASE;
	for (i=sys_irq_base; i < sys_irq_base + M36_NUM_SYS_IRQ; i++)
		irq_set_chip_and_handler(i, &sys_irq_controller,handle_percpu_irq);

	/* Default all ICU IRQs to off and enable IM bit(IP3) of CP0 status for sys IRQ */
#if 	1
	*((unsigned long *)(0xB8000038)) = 0;
	*((unsigned long *)(0xB800003C)) = 0;
	*((unsigned long *)(0xB80000EC)) = 0;
	write_c0_status(read_c0_status() | STATUSF_IP3);
#else
	*M6303_MSYSINT1REG = 0;
	*M6303_MSYSINT2REG = 0;
#endif 

#ifdef CONFIG_REMOTE_DEBUG
	printk("Setting debug traps - please connect the remote debugger.\n");

	set_debug_traps();

	// you may move this line to whereever you want
	breakpoint();
#endif

	if((*(unsigned short *)0xB8000002 == 0x3901)  \
      || (*(unsigned short *)0xB8000002 == 0x3701) \
	  || (*(unsigned short *)0xB8000002 == 0x3503))
	{
		sys_rpc_addr = 0xB8040037;
		sys_rpc_mask = 0x0C;
		sys_rpc_irq1_mask = 0x08;
		sys_rpc_irq2_mask = 0x04;
	}
	else
	{
		sys_rpc_addr = 0xB8040036;
		sys_rpc_mask = 0xC0;
		sys_rpc_irq1_mask = 0x80;
		sys_rpc_irq2_mask = 0x40;		
	}
}
Пример #20
0
void trap_init(){
    volatile uint32_t status;
    volatile uint8_t *p1,*p2,*p3;
    p1 = (uint8_t*)0x80000000;
    p2 = (uint8_t*)_TRAP_HANDLER;
    p3 = p2+sizeof(_TRAP_HANDLER);
    for(;p2<p3;++p2){
        *p1=*p2;
        ++p1;
    }
    status = read_c0_status();
    status |= ST_BEV;
    status ^= ST_BEV;
    write_c0_status(status);
}
void set_trap_handler() {
	uint32_t cp0_status=read_c0_status();
	cp0_status	|=ST_EXL
				|ST_BEV
				|ST_ERL
				|ST_IE
				|ST_IMx(INT_CLOCK)
				|ST_IMx(INT_CLOCK);
				
	cp0_status	^=ST_EXL
				|ST_BEV
				|ST_ERL;
	write_c0_status(cp0_status);
	memcpy((void*)TLB_REFILL_ENTRY, tlb_refill, INT_ENTRY_SIZE);
	memcpy((void*)GENERIC_EXC_ENTRY, generic_exception,INT_ENTRY_SIZE);
	
}
Пример #22
0
/**
 * Enable access to Octeon's COP2 crypto hardware for kernel use.
 * Wrap any crypto operations in calls to
 * octeon_crypto_enable/disable in order to make sure the state of
 * COP2 isn't corrupted if userspace is also performing hardware
 * crypto operations. Allocate the state parameter on the stack.
 *
 * @param state  State structure to store current COP2 state in
 *
 * @return Flags to be passed to octeon_crypto_disable()
 */
unsigned long octeon_crypto_enable(struct octeon_cop2_state *state)
{
	int status;
	unsigned long flags;

	local_irq_save(flags);
	status = read_c0_status();
	write_c0_status(status | ST0_CU2);
	if (KSTK_STATUS(current) & ST0_CU2) {
		octeon_cop2_save(&(current->thread.cp2));
		KSTK_STATUS(current) &= ~ST0_CU2;
		status &= ~ST0_CU2;
	} else if (status & ST0_CU2)
		octeon_cop2_save(state);
	local_irq_restore(flags);
	return status & ST0_CU2;
}
Пример #23
0
void handle_mips_systick(void)
{
	/* clear EXL from status */
	uint32_t sr = read_c0_status();
	sr &= ~0x00000002;
	write_c0_status(sr);

	/* Call the interrupt entry routine */
	atomIntEnter();

	/* Call the OS system tick handler */
	atomTimerTick();

	write_c0_compare(read_c0_count() + COUNTER_TICK_COUNT);

	/* Call the interrupt exit routine */
	atomIntExit(TRUE);
}
void handle_tlb_refill(struct trapframe *tf) {
	unsigned long	entryhi=read_c0_entryhi();
	unsigned long	vpn=TLB_VPN(entryhi);
	unsigned long	pfn=pt[ENTRYHI_ASID(entryhi)][vpn];
	if(pfn) {
		unsigned long entrylo=( TLB_PFN(pfn, entryhi) | TLB_COHERENT | TLB_VALID | TLB_DIRTY | TLB_GLOBAL)^TLB_GLOBAL;
		write_c0_entrylo0(entrylo);
		write_c0_entrylo1(TLB_ELO0TO1(entrylo));
		tlbwr();
	} else {
		kprintf("Fatal error, invalied page: %x with ASID= %d, rebooting...\n",vpn, ENTRYHI_ASID(entryhi));
		unsigned long* reg=(unsigned long*)tf;
		write_c0_status((read_c0_status()|ST_KSU)^ST_KSU);
		reg[ORD_STATUS]=(read_c0_status()|ST_KSU)^ST_KSU;
		reg[ORD_EPC]=__reset;
	}
	return;
}
Пример #25
0
/**
 * init hardware FPU
 */
void rt_hw_fpu_init(void)
{
    rt_uint32_t c0_status = 0;
    rt_uint32_t c1_status = 0;

    // 使能协处理器1--FPU
    c0_status = read_c0_status();
    c0_status |= (ST0_CU1 | ST0_FR);
    write_c0_status(c0_status);

    // 配置FPU
    c1_status = read_c1_status();
    c1_status |= (FPU_CSR_FS | FPU_CSR_FO | FPU_CSR_FN);    // set FS, FO, FN
    c1_status &= ~(FPU_CSR_ALL_E);                          // disable exception
    c1_status = (c1_status & (~FPU_CSR_RM)) | FPU_CSR_RN;   // set RN
    write_c1_status(c1_status);

    return ;
}
Пример #26
0
void ds2_init(void)
{
	pfunc *p;
	write_c0_status(0x10000400);

	memcpy((void *)A_K0BASE, except_common_entry, 0x20);
	memcpy((void *)(A_K0BASE + 0x180), except_common_entry, 0x20);
	memcpy((void *)(A_K0BASE + 0x200), except_common_entry, 0x20);

	__dcache_writeback_all();
	__icache_invalidate_all();

    init_perihery();
    InitExcept();
	_intc_init();

	detect_clock();

//	gpio_init();
//	serial_init();
    pm_init();
	//dgprintf("\n\nOS initial!\n");

//	OSInit();
    /* Invoke constroctor functions when needed. */
#if 1	
	for (p=&__CTOR_END__[-1]; p >= __CTOR_LIST__; p--)
	{
		printf("create class %08x\n",p);
		
		(*p)();
    }
	
	//dgprintf("Before main function\n");
#endif

	//Start system ticker
	_StartSysTimer();

	//enable global interrupt
	sti();
}
Пример #27
0
void __init init_IRQ(void)
{
	int flags;
//	printk("\nfile %s cp0 status %x\n",__FILE__,read_c0_status());
	flags = read_c0_status();
	flags |= CAUSEF_IP4|CAUSEF_IP3|CAUSEF_IP5|0xfc00;
	write_c0_status(flags);	
	//printk("\nfile %s cp0 status %x\n",__FILE__,read_c0_status());
#ifdef CONFIG_REMOTE_DEBUG
	extern void breakpoint(void);
	extern void set_debug_traps(void);

	printk("Wait for gdb client connection ...\n");
	set_debug_traps();
	breakpoint();
#endif

	/* Invoke board-specific irq setup */
	irq_setup();
}
Пример #28
0
void __init asic_irq_init(void)
{
	int i;

	/* set priority to 0 */
	write_c0_status(read_c0_status() & ~(0x0000fc00));

	asic_write(0, ien_int_0);
	asic_write(0, ien_int_1);
	asic_write(0, ien_int_2);
	asic_write(0, ien_int_3);

	asic_write(0x0fffffff, int_level_3_3);
	asic_write(0xffffffff, int_level_3_2);
	asic_write(0xffffffff, int_level_3_1);
	asic_write(0xffffffff, int_level_3_0);
	asic_write(0xffffffff, int_level_2_3);
	asic_write(0xffffffff, int_level_2_2);
	asic_write(0xffffffff, int_level_2_1);
	asic_write(0xffffffff, int_level_2_0);
	asic_write(0xffffffff, int_level_1_3);
	asic_write(0xffffffff, int_level_1_2);
	asic_write(0xffffffff, int_level_1_1);
	asic_write(0xffffffff, int_level_1_0);
	asic_write(0xffffffff, int_level_0_3);
	asic_write(0xffffffff, int_level_0_2);
	asic_write(0xffffffff, int_level_0_1);
	asic_write(0xffffffff, int_level_0_0);

	asic_write(0xf, int_int_scan);

	/*
	 * Initialize interrupt handlers.
	 */
	for (i = 0; i < NR_IRQS; i++)
		set_irq_chip_and_handler(i, &asic_irq_chip, handle_level_irq);
}
Пример #29
0
void __init plat_timer_setup(struct irqaction *irq)
{
    unsigned int est_freq;

    printk("calculating r4koff... ");
    r4k_offset = cal_r4koff();
    printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);

    //est_freq = 2*r4k_offset*HZ;
    est_freq = r4k_offset*HZ;
    est_freq += 5000;    /* round */
    est_freq -= est_freq%10000;
    printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
           (est_freq%1000000)*100/1000000);
    set_au1x00_speed(est_freq);
    set_au1x00_lcd_clock(); // program the LCD clock

    r4k_cur = (read_c0_count() + r4k_offset);
    write_c0_compare(r4k_cur);

#ifdef CONFIG_PM
    /*
     * setup counter 0, since it keeps ticking after a
     * 'wait' instruction has been executed. The CP0 timer and
     * counter 1 do NOT continue running after 'wait'
     *
     * It's too early to call request_irq() here, so we handle
     * counter 0 interrupt as a special irq and it doesn't show
     * up under /proc/interrupts.
     *
     * Check to ensure we really have a 32KHz oscillator before
     * we do this.
     */
    if (no_au1xxx_32khz) {
        unsigned int c0_status;

        printk("WARNING: no 32KHz clock found.\n");

        /* Ensure we get CPO_COUNTER interrupts.
        */
        c0_status = read_c0_status();
        c0_status |= IE_IRQ5;
        write_c0_status(c0_status);
    }
    else {
        while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);
        au_writel(0, SYS_TOYWRITE);
        while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S);

        au_writel(au_readl(SYS_WAKEMSK) | (1<<8), SYS_WAKEMSK);
        au_writel(~0, SYS_WAKESRC);
        au_sync();
        while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);

        /* setup match20 to interrupt once every HZ */
        last_pc0 = last_match20 = au_readl(SYS_TOYREAD);
        au_writel(last_match20 + MATCH20_INC, SYS_TOYMATCH2);
        au_sync();
        while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_M20);
        startup_match20_interrupt(counter0_irq);

        /* We can use the real 'wait' instruction.
        */
        allow_au1k_wait = 1;
    }

#endif
}
void handle_exception(struct trapframe *tf) {
	uint32_t cause=read_c0_cause();
	unsigned long* reg=(unsigned long*)tf;
	if(EXCCODE(cause)==EC_int) {
		if(cause&CR_IPx(INT_CLOCK)) {
			if(sc_num!=SYS_NONE) {
				write_c0_compare(NULL);
				return;
			}
			//kprintf("--DEBUG-- CPU%d time out: %d\n",cpuid(),cur_pid);
			pcb[cur_pid].status=ST_READY;
			unsigned long i;
			pcb_save(cur_pid,i);
			next_process;
			pcb_restore(cur_pid,i);
			reg[ORD_ENTRYHI]=cur_pid;
			RESET_CLOCK;
		}
	} else if(EXCCODE(cause)==EC_sys) {
		reg[ORD_EPC]+=INST_SIZE;
		unsigned long i;
		switch(reg[ORD_V0]) {
			case SYS_PID:
				reg[ORD_V0]=cur_pid;
				break;
			case SYS_PPID:
				reg[ORD_V0]=pcb[cur_pid].ppid;
				break;
			case SYS_FORK: {
				sc_pid=cur_pid;
				sc_num=SYS_FORK;
				reg[ORD_STATUS]=(read_c0_status()|ST_KSU)^ST_KSU;
				pcb_save(cur_pid, i);
				pcb[cur_pid].status=ST_READY;
				pcb_restore(0, i);
				cur_pid=0;
				break;
			}
			case SYS_EXEC:
				sc_pid=cur_pid;
				sc_num=SYS_EXEC;
				sc_args[0]=reg[ORD_A0];
				reg[ORD_STATUS]=(read_c0_status()|ST_KSU)^ST_KSU;
				pcb_save(cur_pid, i);
				pcb[cur_pid].status=ST_READY;
				pcb_restore(0, i);
				cur_pid=0;
				break;
			case SYS_SLEEP:
				if(reg[ORD_A0]==0)break;
				pcb[cur_pid].compare=read_c0_count()+reg[ORD_A0]*MS_PER_SEC*COUNT_PER_MS;
				pcb[cur_pid].status=ST_BLOCK;
				pcb_save(cur_pid,i);
				next_process;
				pcb_restore(cur_pid,i);
				reg[ORD_ENTRYHI]=cur_pid;
				RESET_CLOCK;
				break;
			case SYS_WAITPID:
				pcb[cur_pid].wait=reg[ORD_A0];
				pcb[cur_pid].status=ST_BLOCK;
				pcb_save(cur_pid,i);
				next_process;
				pcb_restore(cur_pid,i);
				reg[ORD_ENTRYHI]=cur_pid;
				RESET_CLOCK;
				break;
			case SYS_MLC:
				reg[ORD_V0]=kmalloc(reg[ORD_A0]);
				break;
			case SYS_PUTS:
				sc_pid=cur_pid;
				sc_num=SYS_PUTS;
				sc_args[0]=reg[ORD_A0];
				reg[ORD_STATUS]=(read_c0_status()|ST_KSU)^ST_KSU;
				pcb_save(cur_pid, i);
				pcb[cur_pid].status=ST_READY;
				pcb_restore(0, i);
				cur_pid=0;
				break;
			case SYS_KNL:
				reg[ORD_STATUS]=(read_c0_status()|ST_KSU)^ST_KSU;
				reg[ORD_V0]=0;
				break;
			case SYS_USR:
				pcb_save(0, i);
				pcb[cur_pid].status=ST_RUNNING;
				pcb_restore(cur_pid, i);
				reg[ORD_ENTRYHI]=cur_pid;
				reg[ORD_STATUS]=(read_c0_status()|ST_KSU)^KSU_SUPERVISOR;
				write_c0_compare(read_c0_count()+TIME_SLICE*COUNT_PER_MS);
				break;
			case SYS_EXIT: {
				kprintf("--DEBUG-- pid %d exited with %d!\n",cur_pid,reg[ORD_A0]);
				pcb[cur_pid].status=ST_STOPED;
				unsigned long max_page=TLB_VPN(pcb[cur_pid].max_addr);
				for(i=0;i<max_page;i++) {
					ppage_free(pt[cur_pid][i]);
					pt[cur_pid][i]=0;
				}
				next_process;
				reg[ORD_ENTRYHI]=cur_pid;
				pcb_restore(cur_pid,i);
				break;
			}
			case SYS_GETS: {
				sc_pid=cur_pid;
				sc_num=SYS_GETS;
				sc_args[0]=reg[ORD_A0];
				sc_args[1]=reg[ORD_A1];
				reg[ORD_STATUS]=(read_c0_status()|ST_KSU)^ST_KSU;
				pcb_save(cur_pid, i);
				pcb[cur_pid].status=ST_READY;
				pcb_restore(0, i);
				cur_pid=0;
				break;
			}
		}
	} else {
		kputs("Fatal error, unkown exception, rebooting...\n");
		write_c0_status((read_c0_status()|ST_KSU)^ST_KSU);
		reg[ORD_STATUS]=(read_c0_status()|ST_KSU)^ST_KSU;
		reg[ORD_EPC]=__reset;
	}
	return;
}