summaryrefslogtreecommitdiff
path: root/kernel/support.c
diff options
context:
space:
mode:
authorFreya Murphy <freya@freyacat.org>2025-03-25 17:36:52 -0400
committerFreya Murphy <freya@freyacat.org>2025-03-25 17:38:22 -0400
commit6af21e6a4f2251e71353562d5df7f376fdffc270 (patch)
treede20c7afc9878422c81e34f30c6b010075e9e69a /kernel/support.c
downloadcomus-6af21e6a4f2251e71353562d5df7f376fdffc270.tar.gz
comus-6af21e6a4f2251e71353562d5df7f376fdffc270.tar.bz2
comus-6af21e6a4f2251e71353562d5df7f376fdffc270.zip
initial checkout from wrc
Diffstat (limited to 'kernel/support.c')
-rw-r--r--kernel/support.c279
1 files changed, 279 insertions, 0 deletions
diff --git a/kernel/support.c b/kernel/support.c
new file mode 100644
index 0000000..d48ce59
--- /dev/null
+++ b/kernel/support.c
@@ -0,0 +1,279 @@
+/*
+** SCCS ID: @(#)support.c 2.6 1/22/25
+**
+** @file support.c
+**
+** @author 4003-506 class of 20003
+** @authors K. Reek, Warren R. Carithers
+**
+** Miscellaneous system initialization functions, interrupt
+** support routines, and data structures.
+*/
+
+#include <common.h>
+
+#include <support.h>
+#include <cio.h>
+#include <x86/arch.h>
+#include <x86/pic.h>
+#include <x86/ops.h>
+#include <bootstrap.h>
+#include <syscalls.h>
+
+/*
+** Global variables and local data types.
+*/
+
+/*
+** This is the table that contains pointers to the C-language ISR for
+** each interrupt. These functions are called from the isr stub based
+** on the interrupt number.
+*/
+void ( *isr_table[ 256 ] )( int vector, int code );
+
+/*
+** Format of an IDT entry.
+*/
+typedef struct {
+ short offset_15_0;
+ short segment_selector;
+ short flags;
+ short offset_31_16;
+} IDT_Gate;
+
+/*
+** LOCAL ROUTINES - not intended to be used outside this module.
+*/
+
+/**
+** unexpected_handler
+**
+** This routine catches interrupts that we do not expect to ever occur.
+** It handles them by (optionally) reporting them and then calling panic().
+**
+** @param vector vector number for the interrupt that occurred
+** @param code error code, or a dummy value
+**
+** Does not return.
+*/
+#ifdef RPT_INT_UNEXP
+/* add any header includes you need here */
+#endif
+static void unexpected_handler( int vector, int code ) {
+#ifdef RPT_INT_UNEXP
+ cio_printf( "\n** UNEXPECTED vector %d code %d\n", vector, code );
+#endif
+ panic( "Unexpected interrupt" );
+}
+
+/**
+** default_handler
+**
+** Default handler for interrupts we expect may occur but are not
+** handling (yet). We just reset the PIC and return.
+**
+** @param vector vector number for the interrupt that occurred
+** @param code error code, or a dummy value
+*/
+static void default_handler( int vector, int code ) {
+#ifdef RPT_INT_UNEXP
+ cio_printf( "\n** vector %d code %d\n", vector, code );
+#endif
+ if( vector >= 0x20 && vector < 0x30 ) {
+ if( vector > 0x27 ) {
+ // must also ACK the secondary PIC
+ outb( PIC2_CMD, PIC_EOI );
+ }
+ outb( PIC1_CMD, PIC_EOI );
+ } else {
+ /*
+ ** All the "expected" interrupts will be handled by the
+ ** code above. If we get down here, the isr table may
+ ** have been corrupted. Print a message and don't return.
+ */
+ panic( "Unexpected \"expected\" interrupt!" );
+ }
+}
+
+/**
+** mystery_handler
+**
+** Default handler for the "mystery" interrupt that comes through vector
+** 0x27. This is a non-repeatable interrupt whose source has not been
+** identified, but it appears to be the famous "spurious level 7 interrupt"
+** source.
+**
+** @param vector vector number for the interrupt that occurred
+** @param code error code, or a dummy value
+*/
+static void mystery_handler( int vector, int code ) {
+#if defined(RPT_INT_MYSTERY) || defined(RPT_INT_UNEXP)
+ cio_printf( "\nMystery interrupt!\nVector=0x%02x, code=%d\n",
+ vector, code );
+#endif
+ outb( PIC1_CMD, PIC_EOI );
+}
+
+/**
+** init_pic
+**
+** Initialize the 8259 Programmable Interrupt Controller.
+*/
+static void init_pic( void ) {
+ /*
+ ** ICW1: start the init sequence, update ICW4
+ */
+ outb( PIC1_CMD, PIC_CW1_INIT | PIC_CW1_NEED4 );
+ outb( PIC2_CMD, PIC_CW1_INIT | PIC_CW1_NEED4 );
+
+ /*
+ ** ICW2: primary offset of 0x20 in the IDT, secondary offset of 0x28
+ */
+ outb( PIC1_DATA, PIC1_CW2_VECBASE );
+ outb( PIC2_DATA, PIC2_CW2_VECBASE );
+
+ /*
+ ** ICW3: secondary attached to line 2 of primary, bit mask is 00000100
+ ** secondary id is 2
+ */
+ outb( PIC1_DATA, PIC1_CW3_SEC_IRQ2 );
+ outb( PIC2_DATA, PIC2_CW3_SEC_ID );
+
+ /*
+ ** ICW4: want 8086 mode, not 8080/8085 mode
+ */
+ outb( PIC1_DATA, PIC_CW4_PM86 );
+ outb( PIC2_DATA, PIC_CW4_PM86 );
+
+ /*
+ ** OCW1: allow interrupts on all lines
+ */
+ outb( PIC1_DATA, PIC_MASK_NONE );
+ outb( PIC2_DATA, PIC_MASK_NONE );
+}
+
+/**
+** set_idt_entry
+**
+** Construct an entry in the IDT
+**
+** @param entry the vector number of the interrupt
+** @param handler ISR address to be put into the IDT entry
+**
+** Note: generally, the handler invoked from the IDT will be a "stub"
+** that calls the second-level C handler via the isr_table array.
+*/
+static void set_idt_entry( int entry, void ( *handler )( void ) ) {
+ IDT_Gate *g = (IDT_Gate *)IDT_ADDR + entry;
+
+ g->offset_15_0 = (int)handler & 0xffff;
+ g->segment_selector = 0x0010;
+ g->flags = IDT_PRESENT | IDT_DPL_0 | IDT_INT32_GATE;
+ g->offset_31_16 = (int)handler >> 16 & 0xffff;
+}
+
+/**
+** Name: init_idt
+**
+** Initialize the Interrupt Descriptor Table (IDT). This makes each of
+** the entries in the IDT point to the isr stub for that entry, and
+** installs a default handler in the handler table. Temporary handlers
+** are then installed for those interrupts we may get before a real
+** handler is set up.
+*/
+static void init_idt( void ) {
+ int i;
+ extern void ( *isr_stub_table[ 256 ] )( void );
+
+ /*
+ ** Make each IDT entry point to the stub for that vector. Also
+ ** make each entry in the ISR table point to the default handler.
+ */
+ for ( i=0; i < 256; i++ ) {
+ set_idt_entry( i, isr_stub_table[ i ] );
+ install_isr( i, unexpected_handler );
+ }
+
+ /*
+ ** Install the handlers for interrupts that have (or will have) a
+ ** specific handler. Comments indicate which module init function
+ ** will eventually install the "real" handler.
+ */
+
+ install_isr( VEC_KBD, default_handler ); // cio_init()
+ install_isr( VEC_COM1, default_handler ); // sio_init()
+ install_isr( VEC_TIMER, default_handler ); // clk_init()
+ install_isr( VEC_SYSCALL, default_handler ); // sys_init()
+ install_isr( VEC_PAGE_FAULT, default_handler ); // vm_init()
+
+ install_isr( VEC_MYSTERY, mystery_handler );
+}
+
+/*
+** END OF LOCAL ROUTINES.
+**
+** Full documentation for globally-visible routines is in the corresponding
+** header file.
+*/
+
+/*
+** panic
+**
+** Called when we find an unrecoverable error.
+*/
+void panic( char *reason ) {
+ __asm__( "cli" );
+ cio_printf( "\nPANIC: %s\nHalting...", reason );
+ for(;;) {
+ ;
+ }
+}
+
+/*
+** init_interrupts
+**
+** (Re)initilizes the interrupt system.
+*/
+void init_interrupts( void ) {
+ init_idt();
+ init_pic();
+}
+
+/*
+** install_isr
+**
+** Installs a second-level handler for a specific interrupt.
+*/
+void (*install_isr( int vector,
+ void (*handler)(int,int) ) ) ( int, int ) {
+
+ void ( *old_handler )( int vector, int code );
+
+ old_handler = isr_table[ vector ];
+ isr_table[ vector ] = handler;
+ return old_handler;
+}
+
+/*
+** Name: delay
+**
+** Notes: The parameter to the delay() function is ambiguous; it
+** purports to indicate a delay length, but that isn't really tied
+** to any real-world time measurement.
+**
+** On the original systems we used (dual 500MHz Intel P3 CPUs), each
+** "unit" was approximately one tenth of a second, so delay(10) would
+** delay for about one second.
+**
+** On the current machines (Intel Core i5-7500), delay(100) is about
+** 2.5 seconds, so each "unit" is roughly 0.025 seconds.
+**
+** Ultimately, just remember that DELAY VALUES ARE APPROXIMATE AT BEST.
+*/
+void delay( int length ) {
+
+ while( --length >= 0 ) {
+ for( int i = 0; i < 10000000; ++i )
+ ;
+ }
+}