#ifndef INTERRUPTS_H #define INTERRUPTS_H #include "stdint.h" #include "port.h" #include "tasks.h" // total number of supported interrupts #define NOF_INTERRUPTS 256 // offset for hardware interrupts #define IRQ_BASE 0x20 // TODO: for now the code segment is the first entry in the boot GDT // temporary, should be a gdt module with functions to retrieve the // current code segment selector #define GDT_CODE_SEGMENT_SELECTOR 8 // TCC 0.9.26 bug?, __attribute__( ( packed ) ) on structs not working, // also not working on members.. resorting to pragmas #if defined( __TINYC__ ) #pragma pack(1) #endif // packed IDT structure, note TCC needs every member to have a packed // attribute, GCC/Clang are happy with the packed attribute at the // structure level typedef struct interrupt_gate_descriptor_t { uint16_t handler_address_low_bits; uint16_t gdt_code_segment_selector; uint8_t reserved; uint8_t access; uint16_t handler_address_high_bits; } __attribute__( ( packed ) ) interrupt_gate_descriptor_t; #if defined( __TINYC__ ) #pragma pack() #endif #if defined( __TINYC__ ) #pragma pack(1) #endif typedef struct { uint16_t size; uint32_t base; } __attribute__( ( packed ) ) interrupt_descriptor_table_pointer_t; #if defined( __TINYC__ ) #pragma pack() #endif struct interrupt_t; struct interrupt_handler_t; typedef uint32_t (*interrupt_handler_func_t)( struct interrupt_handler_t *handler, uint32_t esp ); typedef struct interrupt_handler_t { uint8_t interrupt_no; struct interrupt_t *interrupt; interrupt_handler_func_t handle; void *driver; } interrupt_handler_t; void interrupt_handler_init_void( interrupt_handler_t *handler, struct interrupt_t *interrupt ); void interrupt_handler_init( interrupt_handler_t *handler, uint8_t interrupt_no, struct interrupt_t *interrupt, interrupt_handler_func_t handle, void *driver ); typedef struct interrupt_t { interrupt_descriptor_table_pointer_t idt_pointer; interrupt_gate_descriptor_t descriptor_table[NOF_INTERRUPTS]; interrupt_handler_t interrupt_handler[NOF_INTERRUPTS]; task_manager_t *task_manager; // PIC master control register: command and status register port8_t PIC_master_control; // PIC master data register: interrupt mask and data register 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 ); void interrupts_disable( void ); void interrupts_init( interrupt_t *interrupt, uint16_t gdt_code_segment_selector, task_manager_t *task_manager ); void interrupts_register_interrupt_gate( interrupt_t *interrupt, uint8_t interrupt_no, uint16_t gdt_code_segment_selector, void (*helper_handler)( ), uint8_t privilege_level, uint8_t descriptor_type ); void interrupts_register_interrupt_handler( interrupt_handler_t handler ); void interrupts_load_idt( interrupt_descriptor_table_pointer_t *idt_pointer ); uint32_t interrupts_handle_interrupt( interrupt_t *interrupt, uint8_t interrupt_no, uint32_t esp ); uint32_t interrupts_handle_static_interrupt( uint8_t interrupt_no, uint32_t esp ); uint32_t interrupts_exception_division_by_zero( interrupt_handler_t *handler, uint32_t esp ); uint32_t interrupts_interrupt_PIT( interrupt_handler_t *handler, uint32_t esp ); void interrupts_ignore_request( ); void interrupts_handle_exception_0x00( ); void interrupts_handle_irq_0x00( ); void interrupts_handle_irq_0x01( ); void interrupts_handle_irq_0x0C( ); // later: tasks and stacks, queues #endif // INTERRUPTS_H