mirror of
				https://gitlab.com/sortix/sortix.git
				synced 2023-02-13 20:55:38 -05:00 
			
		
		
		
	Refactor interrupt handler registration.
This commit is contained in:
		
							parent
							
								
									ede6d8f800
								
							
						
					
					
						commit
						59262f6bf2
					
				
					 6 changed files with 76 additions and 24 deletions
				
			
		| 
						 | 
				
			
			@ -415,6 +415,9 @@ static void UARTIRQHandler(struct interrupt_context* /*intctx*/, void* /*user*/)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct interrupt_handler irq3_handler;
 | 
			
		||||
static struct interrupt_handler irq4_handler;
 | 
			
		||||
 | 
			
		||||
void Init(const char* devpath, Ref<Descriptor> slashdev)
 | 
			
		||||
{
 | 
			
		||||
	ioctx_t ctx; SetupKernelIOCtx(&ctx);
 | 
			
		||||
| 
						 | 
				
			
			@ -434,8 +437,11 @@ void Init(const char* devpath, Ref<Descriptor> slashdev)
 | 
			
		|||
			PanicF("Unable to link %s/%s to COM port driver.", devpath, name);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	Interrupt::RegisterHandler(Interrupt::IRQ3, UARTIRQHandler, NULL);
 | 
			
		||||
	Interrupt::RegisterHandler(Interrupt::IRQ4, UARTIRQHandler, NULL);
 | 
			
		||||
	irq3_handler.handler = UARTIRQHandler;
 | 
			
		||||
	irq4_handler.handler = UARTIRQHandler;
 | 
			
		||||
 | 
			
		||||
	Interrupt::RegisterHandler(Interrupt::IRQ3, &irq3_handler);
 | 
			
		||||
	Interrupt::RegisterHandler(Interrupt::IRQ4, &irq4_handler);
 | 
			
		||||
 | 
			
		||||
	// Initialize the ports so we can transfer data.
 | 
			
		||||
	for ( size_t i = 1; i <= NUMCOMPORTS; i++ )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,6 +31,21 @@
 | 
			
		|||
#include <sortix/kernel/registers.h>
 | 
			
		||||
 | 
			
		||||
namespace Sortix {
 | 
			
		||||
 | 
			
		||||
struct interrupt_context;
 | 
			
		||||
 | 
			
		||||
struct interrupt_handler
 | 
			
		||||
{
 | 
			
		||||
	void (*handler)(struct interrupt_context*, void*);
 | 
			
		||||
	void* context;
 | 
			
		||||
	struct interrupt_handler* next;
 | 
			
		||||
	struct interrupt_handler* prev;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Sortix
 | 
			
		||||
 | 
			
		||||
namespace Sortix {
 | 
			
		||||
 | 
			
		||||
namespace Interrupt {
 | 
			
		||||
 | 
			
		||||
#if defined(__i386__) || defined(__x86_64__)
 | 
			
		||||
| 
						 | 
				
			
			@ -100,9 +115,8 @@ inline bool SetEnabled(bool is_enabled)
 | 
			
		|||
	return wasenabled;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef void (*Handler)(struct interrupt_context* intctx, void* user);
 | 
			
		||||
void RegisterHandler(unsigned int index, Handler handler, void* user);
 | 
			
		||||
void RegisterHandler(unsigned int index, struct interrupt_handler* handler);
 | 
			
		||||
void UnregisterHandler(unsigned int index, struct interrupt_handler* handler);
 | 
			
		||||
 | 
			
		||||
void Init();
 | 
			
		||||
void InitWorker();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,7 +76,9 @@ PS2Keyboard::PS2Keyboard(uint16_t iobase, uint8_t interrupt)
 | 
			
		|||
	this->leds = 0;
 | 
			
		||||
	this->scancodeescaped = false;
 | 
			
		||||
	this->kblock = KTHREAD_MUTEX_INITIALIZER;
 | 
			
		||||
	Interrupt::RegisterHandler(interrupt, PS2Keyboard__OnInterrupt, this);
 | 
			
		||||
	interrupt_registration.handler = PS2Keyboard__OnInterrupt;
 | 
			
		||||
	interrupt_registration.context = this;
 | 
			
		||||
	Interrupt::RegisterHandler(interrupt, &interrupt_registration);
 | 
			
		||||
 | 
			
		||||
	// If any scancodes were already pending, our interrupt handler will
 | 
			
		||||
	// never be called. Let's just discard anything pending.
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +87,7 @@ PS2Keyboard::PS2Keyboard(uint16_t iobase, uint8_t interrupt)
 | 
			
		|||
 | 
			
		||||
PS2Keyboard::~PS2Keyboard()
 | 
			
		||||
{
 | 
			
		||||
	Interrupt::RegisterHandler(interrupt, NULL, NULL);
 | 
			
		||||
	Interrupt::RegisterHandler(interrupt, &interrupt_registration);
 | 
			
		||||
	delete[] queue;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,6 +28,7 @@
 | 
			
		|||
#include <stddef.h>
 | 
			
		||||
#include <stdint.h>
 | 
			
		||||
 | 
			
		||||
#include <sortix/kernel/interrupt.h>
 | 
			
		||||
#include <sortix/kernel/kthread.h>
 | 
			
		||||
#include <sortix/kernel/keyboard.h>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -56,6 +57,7 @@ private:
 | 
			
		|||
	void NotifyOwner();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
	struct interrupt_handler interrupt_registration;
 | 
			
		||||
	int* queue;
 | 
			
		||||
	size_t queuelength;
 | 
			
		||||
	size_t queueoffset;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -134,16 +134,35 @@ const char* exception_names[] =
 | 
			
		|||
const unsigned int NUM_INTERRUPTS = 256U;
 | 
			
		||||
 | 
			
		||||
static struct IDT::idt_entry interrupt_table[NUM_INTERRUPTS];
 | 
			
		||||
static Handler interrupt_handlers[NUM_INTERRUPTS];
 | 
			
		||||
static void* interrupt_handler_context[NUM_INTERRUPTS];
 | 
			
		||||
static struct interrupt_handler* interrupt_handlers[NUM_INTERRUPTS];
 | 
			
		||||
 | 
			
		||||
void RegisterHandler(unsigned int index,
 | 
			
		||||
                     Interrupt::Handler handler,
 | 
			
		||||
                     void* context)
 | 
			
		||||
static struct interrupt_handler Scheduler__InterruptYieldCPU_handler;
 | 
			
		||||
static struct interrupt_handler Signal__DispatchHandler_handler;
 | 
			
		||||
static struct interrupt_handler Signal__ReturnHandler_handler;
 | 
			
		||||
static struct interrupt_handler Scheduler__ThreadExitCPU_handler;
 | 
			
		||||
 | 
			
		||||
void RegisterHandler(unsigned int index, struct interrupt_handler* handler)
 | 
			
		||||
{
 | 
			
		||||
	assert(index < NUM_INTERRUPTS);
 | 
			
		||||
	bool was_enabled = SetEnabled(false);
 | 
			
		||||
	handler->prev = NULL;
 | 
			
		||||
	if ( (handler->next = interrupt_handlers[index]) )
 | 
			
		||||
		handler->next->prev = handler;
 | 
			
		||||
	interrupt_handlers[index] = handler;
 | 
			
		||||
	interrupt_handler_context[index] = context;
 | 
			
		||||
	SetEnabled(was_enabled);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void UnregisterHandler(unsigned int index, struct interrupt_handler* handler)
 | 
			
		||||
{
 | 
			
		||||
	assert(index < NUM_INTERRUPTS);
 | 
			
		||||
	bool was_enabled = SetEnabled(false);
 | 
			
		||||
	if ( handler->prev )
 | 
			
		||||
		handler->prev->next = handler->next;
 | 
			
		||||
	else
 | 
			
		||||
		interrupt_handlers[index] = handler->next;
 | 
			
		||||
	if ( handler->next )
 | 
			
		||||
		handler->next->prev = handler->prev;
 | 
			
		||||
	SetEnabled(was_enabled);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void RegisterRawHandler(unsigned int index,
 | 
			
		||||
| 
						 | 
				
			
			@ -168,11 +187,7 @@ void Init()
 | 
			
		|||
	// Initialize the interrupt table entries to the null interrupt handler.
 | 
			
		||||
	memset(&interrupt_table, 0, sizeof(interrupt_table));
 | 
			
		||||
	for ( unsigned int i = 0; i < NUM_INTERRUPTS; i++ )
 | 
			
		||||
	{
 | 
			
		||||
		interrupt_handlers[i] = NULL;
 | 
			
		||||
		interrupt_handler_context[i] = NULL;
 | 
			
		||||
		RegisterRawHandler(i, interrupt_handler_null, false, false);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Remap the IRQ table on the PICs.
 | 
			
		||||
	PIC::ReprogramPIC();
 | 
			
		||||
| 
						 | 
				
			
			@ -231,10 +246,14 @@ void Init()
 | 
			
		|||
	RegisterRawHandler(131, isr131, true, true);
 | 
			
		||||
	RegisterRawHandler(132, thread_exit_handler, true, false);
 | 
			
		||||
 | 
			
		||||
	RegisterHandler(129, Scheduler::InterruptYieldCPU, NULL);
 | 
			
		||||
	RegisterHandler(130, Signal::DispatchHandler, NULL);
 | 
			
		||||
	RegisterHandler(131, Signal::ReturnHandler, NULL);
 | 
			
		||||
	RegisterHandler(132, Scheduler::ThreadExitCPU, NULL);
 | 
			
		||||
	Scheduler__InterruptYieldCPU_handler.handler = Scheduler::InterruptYieldCPU;
 | 
			
		||||
	RegisterHandler(129, &Scheduler__InterruptYieldCPU_handler);
 | 
			
		||||
	Signal__DispatchHandler_handler.handler = Signal::DispatchHandler;
 | 
			
		||||
	RegisterHandler(130, &Signal__DispatchHandler_handler);
 | 
			
		||||
	Signal__ReturnHandler_handler.handler = Signal::ReturnHandler;
 | 
			
		||||
	RegisterHandler(131, &Signal__ReturnHandler_handler);
 | 
			
		||||
	Scheduler__ThreadExitCPU_handler.handler = Scheduler::ThreadExitCPU;
 | 
			
		||||
	RegisterHandler(132, &Scheduler__ThreadExitCPU_handler);
 | 
			
		||||
 | 
			
		||||
	IDT::Set(interrupt_table, NUM_INTERRUPTS);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -333,8 +352,13 @@ extern "C" void interrupt_handler(struct interrupt_context* intctx)
 | 
			
		|||
		KernelCrashHandler(intctx);
 | 
			
		||||
	else if ( is_crash && is_in_user )
 | 
			
		||||
		UserCrashHandler(intctx);
 | 
			
		||||
	else if ( interrupt_handlers[int_no] )
 | 
			
		||||
		interrupt_handlers[int_no](intctx, interrupt_handler_context[int_no]);
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		for ( struct interrupt_handler* iter = interrupt_handlers[int_no];
 | 
			
		||||
		      iter;
 | 
			
		||||
		      iter = iter->next )
 | 
			
		||||
			iter->handler(intctx, iter->context);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Send an end of interrupt signal to the PICs if we got an IRQ.
 | 
			
		||||
	if ( IRQ0 <= int_no && int_no <= IRQ15 )
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -74,6 +74,8 @@ static void RequestIRQ0(uint16_t divisor)
 | 
			
		|||
extern Clock* realtime_clock;
 | 
			
		||||
extern Clock* uptime_clock;
 | 
			
		||||
 | 
			
		||||
struct interrupt_handler timer_interrupt_registration;
 | 
			
		||||
 | 
			
		||||
static struct timespec tick_period;
 | 
			
		||||
static long tick_frequency;
 | 
			
		||||
static uint16_t tick_divisor;
 | 
			
		||||
| 
						 | 
				
			
			@ -126,7 +128,9 @@ void InitializeProcessClocks(Process* process)
 | 
			
		|||
void Start()
 | 
			
		||||
{
 | 
			
		||||
	// Handle timer interrupts if they arrive.
 | 
			
		||||
	Interrupt::RegisterHandler(Interrupt::IRQ0, &OnIRQ0, NULL);
 | 
			
		||||
	timer_interrupt_registration.handler = OnIRQ0;
 | 
			
		||||
	timer_interrupt_registration.context = 0;
 | 
			
		||||
	Interrupt::RegisterHandler(Interrupt::IRQ0, &timer_interrupt_registration);
 | 
			
		||||
 | 
			
		||||
	// Request a timer interrupt now that we can handle them safely.
 | 
			
		||||
	RequestIRQ0(tick_divisor);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue