Added ISRs and IRQs drivers and set up all interrupts in assembly, however the does not work, yet

This commit is contained in:
ice-bit 2019-07-05 18:25:58 +02:00
parent 1aa6963e84
commit bb78281aaf
10 changed files with 385 additions and 2 deletions

View File

@ -1,4 +1,4 @@
OBJS = multiboot.asm.o kernel_loader.asm.o ports.asm.o gdt.asm.o idt.asm.o
OBJS = multiboot.asm.o kernel_loader.asm.o ports.asm.o gdt.asm.o idt.asm.o interrupts.asm.o
ASM = nasm
ASMFLAGS = -f elf

View File

@ -1,3 +1,10 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; iceOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/iceOS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
global gdt_flush ; for drivers/gdt.c
section .text

View File

@ -1,3 +1,10 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; iceOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/iceOS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
global idt_flush ; for drivers/idt.c
section .text

159
kernel/cpu/interrupts.asm Normal file
View File

@ -0,0 +1,159 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; iceOS Kernel ;
; Developed by Marco 'icebit' Cetica ;
; (c) 2019 ;
; Released under GPLv3 ;
; https://github.com/ice-bit/iceOS ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
extern isr_handler ; Defined in drivers/isr.h
extern irq_handler ; Defined in drivers/isr.h
; Let's implement all ISR in a very handy way
%macro ISR_NOERRCODE 1
global isr%1
isr%1:
cli ; Disable interrupts
push byte 0 ; Push dummy error code
push byte 1 ; Push interrupt number
jmp isr_common ; goto ISR handler
%endmacro
%macro ISR_ERRCODE 1
global isr%1
isr%1:
cli ; Disable interrupts
push byte %1 ; Push interrupt number
jmp isr_common ; goto ISR handler
%endmacro
; Now we have to do the same thing for Interrupt Requests,
; in this case the first parameter is the IRQ number while
; the second one is the ISR number to be remapped to
%macro IRQ 2
global irq%1
irq%1:
cli ; Disable interrupts
push byte 0 ; Push dummy error code
push byte %2 ; Push interrupt number
jmp irq_common ; goto IRQ handler
%endmacro
; isr_common is a common handler for all
; Interrupt Service Routines declared in the system
; It's main scope is to save current register's states
; into the stack, call the C high level handler
; and restore the register's original values from
; the stack
isr_common:
;; Save register's content into the stack ;;
pusha ; Push edi,esi,ebp,esp,ebx,edx,ecx,eax
mov ax, ds ; Get 16 bits of eax(e.g ds)
push eax
mov ax, 0x10 ; Load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
;; Call C handler ;;
call isr_handler ; Call C handler
;; Restore register's content from the stack ;;
pop eax ; Restore original data segment selector
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
popa ; Pop edi,esi,ebp,esp,ebx,edx,ecx,eax
add esp, 8 ; Cleans up pushed error code and ISR number
sti ; Re-enable interrupts
iret ; Pops 5 things: CS, EIP, EFLAGS, SS and ESp
; irq_common is a common handler for all
; Interrupt Requests, it's very similar to the
; ISR one
irq_common:
;; Save register's content into the stack ;;
pusha ; Push edi,esi,ebp,esp,ebx,edx,ecx,eax
mov ax, ds ; Get 16 bits of eax(e.g ds)
push eax
mov ax, 0x10 ; Load the kernel data segment descriptor
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
;; Call C handler ;;
call irq_handler ; Call C handler
;; Restore register's content from the stack ;;
pop ebx ; Restore original data segment selector
mov ds, bx
mov es, bx
mov fs, bx
mov gs, bx
popa ; Pop edi,esi,ebp,esp,ebx,edx,ecx,eax
add esp, 8 ; Cleans up pushed error code and ISR number
sti ; Re-enable interrupts
iret ; Pops 5 things: CS, EIP, EFLAGS, SS and ESp
; Standard x86 ISRs (only 8,10-14 and 17 requires to push error codes to the stack)
ISR_NOERRCODE 0
ISR_NOERRCODE 1
ISR_NOERRCODE 2
ISR_NOERRCODE 3
ISR_NOERRCODE 4
ISR_NOERRCODE 5
ISR_NOERRCODE 6
ISR_NOERRCODE 7
ISR_ERRCODE 8
ISR_NOERRCODE 9
ISR_ERRCODE 10
ISR_ERRCODE 11
ISR_ERRCODE 12
ISR_ERRCODE 13
ISR_ERRCODE 14
ISR_NOERRCODE 15
ISR_NOERRCODE 16
ISR_ERRCODE 17
ISR_NOERRCODE 18
ISR_NOERRCODE 19
ISR_NOERRCODE 20
ISR_NOERRCODE 21
ISR_NOERRCODE 22
ISR_NOERRCODE 23
ISR_NOERRCODE 24
ISR_NOERRCODE 25
ISR_NOERRCODE 26
ISR_NOERRCODE 27
ISR_NOERRCODE 28
ISR_NOERRCODE 29
ISR_NOERRCODE 30
ISR_NOERRCODE 31
IRQ 0, 32
IRQ 1, 33
IRQ 2, 34
IRQ 3, 35
IRQ 4, 36
IRQ 5, 37
IRQ 6, 38
IRQ 7, 39
IRQ 8, 40
IRQ 9, 41
IRQ 10, 42
IRQ 11, 43
IRQ 12, 44
IRQ 13, 45
IRQ 14, 46
IRQ 15, 47

View File

@ -1,4 +1,4 @@
OBJS = tty.o gdt.o idt.o
OBJS = tty.o gdt.o idt.o isr.o
CC = i686-elf-gcc # cross-compiler
CFLAGS = -m32 -fno-stack-protector -ffreestanding -Wall -Wextra -Werror -g -c

View File

@ -1,10 +1,12 @@
#include "idt.h"
#include "../libc/string.h"
#include "ports.h"
// Internal method
extern void idt_flush(idt_ptr_t*); // defined on cpu/idt.asm
static void init_idt();
static void idt_set_gate(uint8_t idx, void(*base), uint16_t selector, idt_flags_t flags);
static void pic_remap(uint8_t offset1, uint8_t offset2);
idt_entry_t idt_entries[256]; // 256 interrupts
idt_ptr_t idt_ptr;
@ -68,6 +70,9 @@ static void init_idt() {
idt_set_gate(30, isr30, 0x08, flags);
idt_set_gate(31, isr31, 0x08, flags);
// Remap PIC
pic_remap(PIC1_START_INTERRUPT, PIC2_START_INTERRUPT);
// Also remap 15 entries for IRQs
idt_set_gate(32, irq0, 0x08, flags);
idt_set_gate(33, irq1, 0x08, flags);
@ -90,5 +95,28 @@ static void init_idt() {
// Finally enable hardware interrupts with an assembly instruction
__asm__ __volatile__ ("sti");
}
// Taken here: http://wiki.osdev.org/8259_PIC
static void pic_remap(uint8_t offset1, uint8_t offset2) {
uint8_t a1, a2;
a1 = inb(PIC1_DATA); // Save masks
a2 = inb(PIC2_DATA);
outb(PIC1_COMMAND, ICW1_INIT+ICW1_ICW4); // Start init sequence
outb(PIC2_COMMAND, ICW1_INIT+ICW1_ICW4);
outb(PIC1_DATA, offset1);
outb(PIC2_DATA, offset2);
outb(PIC1_DATA, 4); // Tell master PIC that there is a slave PIC at IRQ2
outb(PIC1_DATA, 2); // Tell salve PIC it's cascade identity
outb(PIC1_DATA, ICW4_8086);
outb(PIC2_DATA, ICW4_8086);
// Restore saved masks
outb(PIC1_DATA, a1);
outb(PIC2_DATA, a2);
}

View File

@ -23,6 +23,27 @@
// Reserved bits in IDT entries
#define IDT_FLAG_RESERVED 0x0E
// PIC
#define PIC1 0x20 // I/O address for master PIC
#define PIC2 0xA0 // I/O address for slave PIC
#define PIC1_COMMAND PIC1
#define PIC1_DATA (PIC1+1)
#define PIC2_COMMAND PIC2
#define PIC2_DATA (PIC2+1)
#define PIC1_START_INTERRUPT 0x20 // Master PIC after remapping
#define PIC2_START_INTERRUPT 0x28 // Slave PIC after remapping
#define PIC_EOI 0x20 // End of interrupt
#define ICW1_ICW4 0x01
#define ICW1_SINGLE 0x02
#define ICW1_INTERVAL4 0x04
#define ICW1_LEVEL 0x08
#define ICW1_INIT 0x10
#define ICW4_8086 0x01 // 8086/88 (MCS-80/85) mode
#define ICW4_AUTO 0x02
#define ICW4_BUF_SLAVE 0x08
#define ICW4_BUF_MASTER 0x0C
#define ICW4_SFNM 0x10
/* Interrupt Descriptor Table */
/* idt_flags contains access flag of a single IDT entry
* | 0 - 4 | 5 - 6 | 7 |

87
kernel/drivers/isr.c Normal file
View File

@ -0,0 +1,87 @@
#include <stdint.h>
#include "isr.h"
#include "../libc/string.h"
#include "tty.h"
#include "ports.h"
#define PIC1 0x20 // I/O address for master PIC
#define PIC2 0xA0 // I/O address for slave PIC
#define PIC1_COMMAND PIC1
#define PIC1_DATA (PIC1+1)
#define PIC2_COMMAND PIC2
#define PIC2_DATA (PIC2+1)
#define PIC_EOI 0x20 // End Of Interrupt command
// List of messages for known interrupts
uint8_t *interrupts_messages[] = {
(uint8_t*)"Division by Zero", // 0
(uint8_t*)"Debug",
(uint8_t*)"Non-maskable interrupt",
(uint8_t*)"Breakpoint",
(uint8_t*)"Detected overflow",
(uint8_t*)"Out-of-bounds", // 5
(uint8_t*)"Invalid opcode",
(uint8_t*)"No coprocessor",
(uint8_t*)"Double fault",
(uint8_t*)"Coprocessor segment overrun",
(uint8_t*)"Bad TSS", // 10
(uint8_t*)"Segment not present",
(uint8_t*)"Stack fault",
(uint8_t*)"General protection fault",
(uint8_t*)"Page fault",
(uint8_t*)"Unknown interrupt", // 15
(uint8_t*)"Coprocessor fault",
(uint8_t*)"Alignment check",
(uint8_t*)"Machine check",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved",
(uint8_t*)"Reserved"
};
isr_t interrupt_handler[256];
void isr_handler(registers_t regs) {
if(interrupt_handler[regs.int_num] != 0) {
isr_t handler = interrupt_handler[regs.int_num];
handler(regs);
} else {
kprint_c((uint8_t*)"Received interrupt: ", 20, LIGHT_BROWN, BLACK);
kprint_c(interrupts_messages[(uint8_t)regs.int_num],
strlen(interrupts_messages[(uint8_t)regs.int_num]),
WHITE,
BLACK
);
kprint((uint8_t*)"\n");
}
}
void ack_irq(uint32_t int_num) {
// Send and End Of Interrupt(EOF) at the PICs.
if(int_num >= 40)
outb(PIC2_COMMAND, PIC_EOI); // Send reset signal to slave
outb(PIC2_COMMAND, PIC_EOI); // In any case, reset the master
}
void irq_handler(registers_t regs) {
ack_irq(regs.int_num);
if(interrupt_handler[regs.int_num] != 0) {
isr_t handler = interrupt_handler[regs.int_num];
handler(regs);
}
}
void register_interrupt_handler(uint8_t n, isr_t handler) {
interrupt_handler[n] = handler;
}

71
kernel/drivers/isr.h Normal file
View File

@ -0,0 +1,71 @@
/**************************************
* iceOS Kernel *
* Developed by Marco 'icebit' Cetica *
* (c) 2019 *
* Released under GPLv3 *
* https://github.com/ice-bit/iceOS *
***************************************/
#ifndef _ISR_H_
#define _ISR_H_
/*
* When we implement ISRs we have to keep in mind that the first 32 interrupts(and so the
* first 32 ISRs) are reserved by the CPU to signal the kernel about critical actions,
* such as divide-by-zero or a stack overflow/buffer overflow.
*
* Below ther's a list of the first, reserved, interrupts...and yeah, we have to implement
* all of them by ourself(btw in Assembly) :D
*
* 0 - Division by zero exception
* 1 - Debug exception
* 2 - Non maskable interrupt
* 3 - Breakpoint exception
* 4 - Into detected overflow
* 5 - Out of bounds exception
* 6 - Invalid opcode exception
* 7 - No coprocessor exception
* 8 - Double fault (pushes an error code)
* 9 - Coprocessor segment overrun
* 10 - Bad TSS (pushes an error code)
* 11 - Segment not present (pushes an error code)
* 12 - Stack fault (pushes an error code)
* 13 - General protection fault (pushes an error code)
* 14 - Page fault (pushes an error code)
* 15 - Unknown interrupt exception
* 16 - Coprocessor fault
* 17 - Alignment check exception
* 18 - Machine check exception
* 19-31 - Reserved */
#include <stdint.h>
#define IRQ0 32
#define IRQ1 33
#define IRQ2 34
#define IRQ3 35
#define IRQ4 36
#define IRQ5 37
#define IRQ6 38
#define IRQ7 39
#define IRQ8 40
#define IRQ9 41
#define IRQ10 42
#define IRQ11 43
#define IRQ12 44
#define IRQ13 45
#define IRQ14 46
#define IRQ15 47
typedef struct registers {
uint32_t ds; // Data segment
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed with pusha
uint32_t int_num, err_code; // Interrupt number and error code
uint32_t eip, cs, eflags, usereap, ss; // Pushed by CPU
} registers_t;
typedef void (*isr_t)(registers_t);
void ack_irq(uint32_t int_num);
void register_interrupt_handler(uint8_t n, isr_t handler);
#endif

View File

@ -1,11 +1,14 @@
#include "drivers/tty.h"
#include "drivers/gdt.h"
#include "drivers/idt.h"
#include "drivers/isr.h"
#include "libc/stdio.h"
void kernel_main() {
clear_prompt();
init_prompt(); // Initialize frame buffer
gdt_setup(); // Setup Global Descriptor Table
idt_setup(); // Setup Interrupt Descriptor Table
puts("Hello World!");
}