www.pudn.com > COS0.0.1.rar > interrupt.c


/*
 interrupt.c - code to manage interrupts
  
 Author:        Paul Barker
 Part of:       COS
 Created:       02/09/04
 Last Modified: 06/10/04

 Copyright (C) 2004 Paul Barker
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

                     (See file "Copying")
*/

/*
	This has been split from idt.c
*/

#include 

#include 
#include 
#include 

#include 
#include 

// Table of error names, from the Intel manual
static string_t error_table[20] = {
	"Divide error",
	"Reserved #DB",
	"NMI",
	"Breakpoint",
	"Overflow",
	"BOUND range exceeded",
	"Invalid opcode",
	"Device not available / No math coprocessor",
	"Double Fault",
	"Coprocessor segment overrun / reserved",
	"Invalid TSS",
	"Segment not present",
	"Stack segment fault",
	"General protection fault",
	"Page fault",
	"Reserved",
	"x87 Floating-Point Error / Math Fault",
	"Alignment check",
	"Machine check",
	"SIMD Floating-Point exception"
};

// this should be kept up to date with what we load when booting
static word_t irqMask = 0xFFFB;

// Get the master and slave parts of an IRQ mask, straight from GeekOS
#define MASTER(mask) ( (mask) & 0xff )
#define SLAVE(mask) ( ((mask)>>8) & 0xff )

//////////////////////////////////////////////////////////////////////////
// Private functions

// Translate an interrupt error code to the error name
string_t translate_error_code(u8_t i)
{
	if (i > 47)
		return "Other";
	
	if (i > 31)
		return "IRQ";
	
	if (i > 19)
		return "Reserved";
	
	return error_table[i];
}

// taken from GeekOS
static void print_selector( const char* regName, unsigned int value )
{
    TRACE(( "%s: index=%d, ti=%d, rpl=%d\n",
	regName, value >> 3, (value >> 2) & 1, value & 3 ));
}

// dummy interrupt handler
void dummy_interrupt(interrupt_state_t* state)
{
	TRACE((" *** Bad Interrupt ***\n"));
	// dump the whole state, taken from GeekOS, with modifications
	unsigned int errorCode = state->errorCode;
	TRACE(("eax=%x ebx=%x ecx=%x edx=%x\n",
		state->eax, state->ebx, state->ecx, state->edx));
	TRACE(("esi=%x edi=%x ebp=%x\n",
		state->esi, state->edi, state->ebp));
	TRACE(("eip=%x cs=%x eflags=%x\n",
		state->eip, state->cs, state->eflags));
	TRACE(("interrupt number=%d (%s), error code=%d\n",
		state->intNum, translate_error_code(state->intNum),
		errorCode));
	TRACE(("index=%d, TI=%d, IDT=%d, EXT=%d\n",
		errorCode >> 3, (errorCode >> 2) & 1,
		(errorCode >> 1) & 1, errorCode & 1));
		
	print_selector( "cs", state->cs );
	print_selector( "ds", state->ds );
	print_selector( "es", state->es );
	print_selector( "fs", state->fs );
	print_selector( "gs", state->gs );
	
	panic("Cannot recover");
}

//////////////////////////////////////////////////////////////////////////
// Public functions

void int_init()
{
	idt_init();
	
	count_t i;
	for (i = 0; i < IDT_NENTRIES; i++)
		install_handler(i, dummy_interrupt);
}

// enable or disable an irq, mostly taken from GeekOS
void enable_irq(u8_t irq, bool_t enable)
{
	TRACE(("setting irq %d %s\n", irq, (enable ? "on" : "off")));
	u8_t oldMask, newMask, mask;

	if (enable)
		mask = irqMask & ~(1 << irq);
	else
		mask = irqMask | (1 << irq);

	oldMask = MASTER(irqMask);
	newMask = MASTER(mask);
	if ( newMask != oldMask )
	{
		outb(newMask, 0x21);
	}

	oldMask = SLAVE(irqMask);
	newMask = SLAVE(mask);
	if ( newMask != oldMask )
	{
		outb(newMask, 0xA1);
	}

	irqMask = mask;
}