From 8e2b19ccd934a4ff8f41ef3fe833381c71f550f8 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Wed, 31 May 2017 21:50:11 +0200 Subject: interrupt separation between CPU exceptions and hardware IRQs by the PIC, started to program the PICs for interrupt delivery --- doc/LINKS.TODO | 3 +++ src/interrupts.asm | 18 ++++++++++++++++-- src/interrupts.c | 38 +++++++++++++++++++++++++++++++++----- src/interrupts.h | 7 ++++++- src/kernel.c | 32 ++++++++++++++------------------ 5 files changed, 72 insertions(+), 26 deletions(-) diff --git a/doc/LINKS.TODO b/doc/LINKS.TODO index 15ea245..a7b3f15 100644 --- a/doc/LINKS.TODO +++ b/doc/LINKS.TODO @@ -37,3 +37,6 @@ longjmp: http://blog.reverberate.org/2013/05/deep-wizardry-stack-unwinding.html http://prettyos.de +PIC: +http://www.brokenthorn.com/Resources/OSDevPic.html + diff --git a/src/interrupts.asm b/src/interrupts.asm index c21229c..9a05883 100644 --- a/src/interrupts.asm +++ b/src/interrupts.asm @@ -37,13 +37,27 @@ interrupts_ignore_request: ; void interrupts_handle_request_0x00( ); %macro exception_stub 1 -global interrupts_handle_request_%1 -interrupts_handle_request_%1: +global interrupts_handle_exception_%1 +interrupts_handle_exception_%1: mov [interrupt_no], byte %1 + jmp int_entry %endmacro exception_stub 0x00 +; IRQs and exceptions would normally collidate, that's why the +; hardware interrupts must be transposed by an offset +IRQ_BASE equ 0x20 + +%macro irq_stub 1 +global interrupts_handle_irq_%1 +interrupts_handle_irq_%1: + mov [interrupt_no], byte IRQ_BASE + %1 + jmp int_entry +%endmacro + +irq_stub 0x00 + int_entry: ; safe state of interrupted code pusha diff --git a/src/interrupts.c b/src/interrupts.c index 810f105..59f38b8 100644 --- a/src/interrupts.c +++ b/src/interrupts.c @@ -17,6 +17,16 @@ // types of IDT entries #define IDT_TYPE_INTERRUPT_GATE 0xE +// offset for hardware interrupts +#define IRQ_BASE 0x20 +#define IRQ_BASE_MASTER IRQ_BASE +#define IRQ_BASE_SLAVE IRQ_BASE_MASTER + 8 + +// PIC constants + +#define ICW1_ICW4 0x01 // support a 4th initialization word (ICW4) +#define ICW1_INIT 0x10 // bit indicating initialization of chip + void interrupts_init( interrupt_t *interrupt ) { memset( interrupt, 0, sizeof( interrupt_t ) ); @@ -28,16 +38,34 @@ void interrupts_init( interrupt_t *interrupt ) // divide-by-zero exception 0x00 interrupts_register_interrupt( interrupt, 0x00, GDT_CODE_SEGMENT_SELECTOR, - &interrupts_handle_request_0x00, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + &interrupts_handle_exception_0x00, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); - interrupt->idt_pointer.size = 256 * sizeof( interrupt_gate_descriptor_t ) - 1; - interrupt->idt_pointer.base = (uint32_t)interrupt->descriptor_table; - - interrupts_load_idt( &interrupt->idt_pointer ); + // IRQ 0 - PIT - programmable interrupt timer + interrupts_register_interrupt( interrupt, IRQ_BASE + 0x00, GDT_CODE_SEGMENT_SELECTOR, + &interrupts_handle_irq_0x00, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + // IRQ 1 - keyboard + interrupts_register_interrupt( interrupt, IRQ_BASE + 0x00, GDT_CODE_SEGMENT_SELECTOR, + &interrupts_handle_irq_0x00, KERNEL_RING, IDT_TYPE_INTERRUPT_GATE ); + port8_init( &interrupt->PIC_master_control, 0x20 ); port8_init( &interrupt->PIC_master_data, 0x21 ); + port8_init( &interrupt->PIC_slave_control, 0xA0 ); + port8_init( &interrupt->PIC_slave_data, 0xA1 ); + + // initialize hardware management PICs (ICW1) + port8_write( &interrupt->PIC_master_control, ICW1_ICW4 | ICW1_INIT ); + port8_write( &interrupt->PIC_slave_control, ICW1_ICW4 | ICW1_INIT ); + // set IRQ base of both PICS (ICW2) + port8_write( &interrupt->PIC_master_data, IRQ_BASE_MASTER ); + port8_write( &interrupt->PIC_slave_data, IRQ_BASE_SLAVE ); + + // tell CPU where the IDT is + interrupt->idt_pointer.size = 256 * sizeof( interrupt_gate_descriptor_t ) - 1; + interrupt->idt_pointer.base = (uint32_t)interrupt->descriptor_table; + + interrupts_load_idt( &interrupt->idt_pointer ); } void interrupts_register_interrupt( interrupt_t *interrupts, diff --git a/src/interrupts.h b/src/interrupts.h index 593a993..e90506f 100644 --- a/src/interrupts.h +++ b/src/interrupts.h @@ -46,6 +46,10 @@ typedef struct { interrupt_gate_descriptor_t descriptor_table[NOF_INTERRUPT_GATES]; port8_t PIC_master_control; port8_t PIC_master_data; + // since PC/AT we always have a slave PIC, we don't support the PC/XT architecture + // with just one PIC + port8_t PIC_slave_control; + port8_t PIC_slave_data; } interrupt_t; void interrupts_enable( void ); @@ -59,7 +63,8 @@ void interrupts_load_idt( interrupt_descriptor_table_pointer_t *idt_pointer ); uint32_t interrupts_handle_interrupt( uint8_t interrupt_no, uint32_t esp ); void interrupts_ignore_request( ); -void interrupts_handle_request_0x00( ); +void interrupts_handle_exception_0x00( ); +void interrupts_handle_irq_0x00( ); // initialize IDT // handle gates diff --git a/src/kernel.c b/src/kernel.c index 355067a..e33d509 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -11,22 +11,17 @@ static jmp_buf panic_jmp_buf; -static vga_t vga; -static console_t console; -// static serial_t serial; - void entry( void ) { + serial_t serial; + serial_init( &serial ); -// serial_t serial; -// serial_init( &serial ); - -// vga_t vga; + vga_t vga; vga_init( &vga ); vga_set_color( &vga, VGA_COLOR_LIGHT_GREY ); vga_set_background_color( &vga, VGA_COLOR_BLACK ); -// console_t console; + console_t console; console_init( &console ); console_add_vga_output( &console, &vga ); // console_add_serial_output( &console, &serial ); @@ -39,17 +34,18 @@ void entry( void ) puts( "Initializing interrupts" ); interrupt_t interrupt; interrupts_init( &interrupt ); - interrupts_enable( ); - -//~ vga_put_char_at( &vga, 81, 20, 'X' ); // exit point in case of kernel panic, do this as soon as // possible - int v = setjmp( panic_jmp_buf ); - printf( "setjmp returned %d\n", v ); - if( v > 0 ) { + if( setjmp( panic_jmp_buf ) > 0 ) { goto TERMINATE; } + + // TODO: initialize hardware here + + interrupts_enable( ); + +//~ vga_put_char_at( &vga, 81, 20, 'X' ); console_put_string( &console, "Running.." ); @@ -62,9 +58,9 @@ void entry( void ) vga_put_char_at( &vga, x_pos, y_pos, '.' ); x_pos++; // serial_put_char( &serial, '.' ); -int y = 0; -int x = 12 / y; -printf( "Hex number is 0x%X and string is '%s'\n", x, "abaos" ); +//~ int y = 0; +//~ int x = 12 / y; +//~ printf( "Hex number is 0x%X and string is '%s'\n", x, "abaos" ); } vga_put_char_at( &vga, x_pos, y_pos, bar[i%4] ); -- cgit v1.2.3-54-g00ecf