ASM_WRAPPER #3
8
Makefile
8
Makefile
@ -17,7 +17,7 @@ CPPFLAGS += $(foreach dir, $(SUBDIRS), -I$(dir))
|
|||||||
asmsrc=$(wildcard arch/$(ARCH)/boot/*.asm)
|
asmsrc=$(wildcard arch/$(ARCH)/boot/*.asm)
|
||||||
asmobj=$(asmsrc:%.asm=%.o)
|
asmobj=$(asmsrc:%.asm=%.o)
|
||||||
csrc=$(shell find $(SUBDIRS) -type f -name "*.c")# $(wildcard *.c)
|
csrc=$(shell find $(SUBDIRS) -type f -name "*.c")# $(wildcard *.c)
|
||||||
cobj=$(csrc:%.c=%.o) arch/$(ARCH)/cpu_context_switch.o arch/$(ARCH)/irq_pit.o
|
cobj=$(csrc:%.c=%.o) arch/$(ARCH)/cpu_context_switch.o arch/$(ARCH)/irq_pit.o arch/$(ARCH)/irq_wrappers.o arch/$(ARCH)/exception_wrappers.o
|
||||||
deps = $(csrc:%.c=%.d)
|
deps = $(csrc:%.c=%.d)
|
||||||
|
|
||||||
kernel kernel.sym &: $(asmobj) $(cobj) linker.ld
|
kernel kernel.sym &: $(asmobj) $(cobj) linker.ld
|
||||||
@ -34,12 +34,6 @@ fd.iso: kernel
|
|||||||
disk.img:
|
disk.img:
|
||||||
qemu-img create -f qcow2 disk.img 32M
|
qemu-img create -f qcow2 disk.img 32M
|
||||||
|
|
||||||
#https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#x86-Function-Attributes
|
|
||||||
arch/$(ARCH)/exception_handler.o:arch/$(ARCH)/exception_handler.c
|
|
||||||
$(CC) $(CFLAGS) $(CPPFLAGS) -mgeneral-regs-only -c $< -o $@
|
|
||||||
arch/$(ARCH)/irq_handler.o:arch/$(ARCH)/irq_handler.c
|
|
||||||
$(CC) $(CFLAGS) $(CPPFLAGS) -mgeneral-regs-only -c $< -o $@
|
|
||||||
|
|
||||||
%.o:%.asm
|
%.o:%.asm
|
||||||
$(AS) $(ASFLAGS) -o $@ $<
|
$(AS) $(ASFLAGS) -o $@ $<
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ To generate iso image
|
|||||||
|
|
||||||
you can also test it
|
you can also test it
|
||||||
|
|
||||||
`make self_test`
|
`make test`
|
||||||
|
|
||||||
# Debug
|
# Debug
|
||||||
|
|
||||||
|
@ -1,12 +1,29 @@
|
|||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
|
#include "cpu_context.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "irq.h"
|
#include "irq.h"
|
||||||
|
#include "klibc.h"
|
||||||
|
#include "kthread.h"
|
||||||
|
#include "vga.h"
|
||||||
|
|
||||||
exception_handler exception_handler_array[EXCEPTION_NUM] = {
|
exception_handler exception_handler_array[EXCEPTION_NUM] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern vaddr_t exception_handler_wrapper_array[EXCEPTION_NUM];
|
||||||
|
|
||||||
|
void exception_handler_wrap(int intr, struct cpu_state *frame)
|
||||||
|
{
|
||||||
|
if (0 > intr || EXCEPTION_NUM <= intr) {
|
||||||
|
pr_err("Trying to handle unknow exception %d\n", intr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exception_handler_array[intr] != NULL)
|
||||||
|
exception_handler_array[intr](frame, intr);
|
||||||
|
}
|
||||||
|
|
||||||
int exceptionSetRoutine(int exception, exception_handler handler)
|
int exceptionSetRoutine(int exception, exception_handler handler)
|
||||||
{
|
{
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
@ -17,54 +34,42 @@ int exceptionSetRoutine(int exception, exception_handler handler)
|
|||||||
|
|
||||||
exception_handler_array[exception] = handler;
|
exception_handler_array[exception] = handler;
|
||||||
|
|
||||||
idt_set_handler(EXCEPTION_INTERRUPT_BASE_ADDRESS + exception, (unsigned int)handler, 0);
|
idt_set_handler(EXCEPTION_INTERRUPT_BASE_ADDRESS + exception,
|
||||||
|
(unsigned int)exception_handler_wrapper_array[exception], 0);
|
||||||
restore_IRQs(flags);
|
restore_IRQs(flags);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void print_handler(struct cpu_state *frame, ulong intr)
|
||||||
|
{
|
||||||
|
int intNbInt = intr;
|
||||||
|
VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %d %d", intNbInt, intr);
|
||||||
|
printf("Exception %d (Err %d) at 0x%x\n", intr, intr,
|
||||||
|
cpu_context_get_PC(frame));
|
||||||
|
asm("hlt");
|
||||||
|
}
|
||||||
|
|
||||||
|
void pagefault_handler(struct cpu_state *frame, ulong intr)
|
||||||
|
{
|
||||||
|
// A page fault has occurred.
|
||||||
|
// The faulting address is stored in the CR2 register.
|
||||||
|
uint32_t faulting_address;
|
||||||
|
asm volatile("mov %%cr2, %0" : "=r"(faulting_address));
|
||||||
|
|
||||||
|
struct kthread *current = getCurrentThread();
|
||||||
|
printf("page fault while in thread %s at 0x%x 0x%x\n", current->name, faulting_address,
|
||||||
|
cpu_context_get_PC(frame));
|
||||||
|
VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", intr);
|
||||||
|
(void)intr;
|
||||||
|
for (;;)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
int exceptionSetup()
|
int exceptionSetup()
|
||||||
{
|
{
|
||||||
exceptionSetRoutine(EXCEPTION_DOUBLE_FAULT, ACCESS_INTERRUPT(EXCEPTION_DOUBLE_FAULT));
|
for (int i = 0; i < EXCEPTION_NUM; i++) {
|
||||||
exceptionSetRoutine(EXCEPTION_DIVIDE_ZERO, ACCESS_INTERRUPT(EXCEPTION_DIVIDE_ZERO));
|
exceptionSetRoutine(i, print_handler);
|
||||||
// Used by the DBG
|
}
|
||||||
// exceptionSetRoutine(EXCEPTION_DEBUG, ACCESS_INTERRUPT(EXCEPTION_DEBUG));
|
|
||||||
exceptionSetRoutine(EXCEPTION_NMI, ACCESS_INTERRUPT(EXCEPTION_NMI));
|
|
||||||
exceptionSetRoutine(EXCEPTION_BREAKPOINT, ACCESS_INTERRUPT(EXCEPTION_BREAKPOINT));
|
|
||||||
exceptionSetRoutine(EXCEPTION_OVERFLOW, ACCESS_INTERRUPT(EXCEPTION_OVERFLOW));
|
|
||||||
exceptionSetRoutine(EXCEPTION_BOUND_RANGE_EXCEEDED,
|
|
||||||
ACCESS_INTERRUPT(EXCEPTION_BOUND_RANGE_EXCEEDED));
|
|
||||||
exceptionSetRoutine(EXCEPTION_INVALID_OPCODE, ACCESS_INTERRUPT(EXCEPTION_INVALID_OPCODE));
|
|
||||||
exceptionSetRoutine(EXCEPTION_DEVICE_NOT_AVAILABLE,
|
|
||||||
ACCESS_INTERRUPT(EXCEPTION_DEVICE_NOT_AVAILABLE));
|
|
||||||
exceptionSetRoutine(EXCEPTION_COPRO_OVERRUN, ACCESS_INTERRUPT(EXCEPTION_COPRO_OVERRUN));
|
|
||||||
exceptionSetRoutine(EXCEPTION_INVALID_TSS, ACCESS_INTERRUPT(EXCEPTION_INVALID_TSS));
|
|
||||||
exceptionSetRoutine(EXCEPTION_SEGMENT_NOT_PRESENT,
|
|
||||||
ACCESS_INTERRUPT(EXCEPTION_SEGMENT_NOT_PRESENT));
|
|
||||||
exceptionSetRoutine(EXCEPTION_STACK_SEGMENT_FAULT,
|
|
||||||
ACCESS_INTERRUPT(EXCEPTION_STACK_SEGMENT_FAULT));
|
|
||||||
exceptionSetRoutine(EXCEPTION_GENERAL_PROTECTION_FAULT,
|
|
||||||
ACCESS_INTERRUPT(EXCEPTION_GENERAL_PROTECTION_FAULT));
|
|
||||||
exceptionSetRoutine(EXCEPTION_PAGE_FAULT, ACCESS_INTERRUPT(EXCEPTION_PAGE_FAULT));
|
|
||||||
exceptionSetRoutine(EXCEPTION_RESERVED_1, ACCESS_INTERRUPT(EXCEPTION_RESERVED_1));
|
|
||||||
exceptionSetRoutine(EXCEPTION_X87_FP_EXCEPTION,
|
|
||||||
ACCESS_INTERRUPT(EXCEPTION_X87_FP_EXCEPTION));
|
|
||||||
exceptionSetRoutine(EXCEPTION_ALIGNMENT_CHECK,
|
|
||||||
ACCESS_INTERRUPT(EXCEPTION_ALIGNMENT_CHECK));
|
|
||||||
exceptionSetRoutine(EXCEPTION_MACHINE_CHECK, ACCESS_INTERRUPT(EXCEPTION_MACHINE_CHECK));
|
|
||||||
exceptionSetRoutine(EXCEPTION_SIMD_FP, ACCESS_INTERRUPT(EXCEPTION_SIMD_FP));
|
|
||||||
exceptionSetRoutine(EXCEPTION_VIRTUALIZATION, ACCESS_INTERRUPT(EXCEPTION_VIRTUALIZATION));
|
|
||||||
exceptionSetRoutine(EXCEPTION_RESERVED_2, ACCESS_INTERRUPT(EXCEPTION_RESERVED_2));
|
|
||||||
exceptionSetRoutine(EXCEPTION_RESERVED_3, ACCESS_INTERRUPT(EXCEPTION_RESERVED_3));
|
|
||||||
exceptionSetRoutine(EXCEPTION_RESERVED_4, ACCESS_INTERRUPT(EXCEPTION_RESERVED_4));
|
|
||||||
exceptionSetRoutine(EXCEPTION_RESERVED_5, ACCESS_INTERRUPT(EXCEPTION_RESERVED_5));
|
|
||||||
exceptionSetRoutine(EXCEPTION_RESERVED_6, ACCESS_INTERRUPT(EXCEPTION_RESERVED_6));
|
|
||||||
exceptionSetRoutine(EXCEPTION_RESERVED_7, ACCESS_INTERRUPT(EXCEPTION_RESERVED_7));
|
|
||||||
exceptionSetRoutine(EXCEPTION_RESERVED_8, ACCESS_INTERRUPT(EXCEPTION_RESERVED_8));
|
|
||||||
exceptionSetRoutine(EXCEPTION_RESERVED_9, ACCESS_INTERRUPT(EXCEPTION_RESERVED_9));
|
|
||||||
exceptionSetRoutine(EXCEPTION_RESERVED_10, ACCESS_INTERRUPT(EXCEPTION_RESERVED_10));
|
|
||||||
exceptionSetRoutine(EXCEPTION_SECURITY, ACCESS_INTERRUPT(EXCEPTION_SECURITY));
|
|
||||||
exceptionSetRoutine(EXCEPTION_RESERVED_11, ACCESS_INTERRUPT(EXCEPTION_RESERVED_11));
|
|
||||||
|
|
||||||
exceptionSetRoutine(EXCEPTION_PAGE_FAULT, pagefault_handler);
|
exceptionSetRoutine(EXCEPTION_PAGE_FAULT, pagefault_handler);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "cpu_context.h"
|
||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "stdarg.h"
|
#include "stdarg.h"
|
||||||
|
|
||||||
@ -39,8 +40,8 @@
|
|||||||
#define EXCEPTION_SECURITY 30
|
#define EXCEPTION_SECURITY 30
|
||||||
#define EXCEPTION_RESERVED_11 31
|
#define EXCEPTION_RESERVED_11 31
|
||||||
|
|
||||||
#define EXCEPTION_NUM 32
|
#define EXCEPTION_NUM 0x20
|
||||||
|
|
||||||
typedef void (*exception_handler)(struct interrupt_frame *frame, ulong error_code);
|
typedef void (*exception_handler)(struct cpu_state *frame, ulong intr_number);
|
||||||
int exceptionSetRoutine(int exception, exception_handler handler);
|
int exceptionSetRoutine(int exception, exception_handler handler);
|
||||||
int exceptionSetup();
|
int exceptionSetup();
|
||||||
|
@ -1,71 +0,0 @@
|
|||||||
#include "exception.h"
|
|
||||||
#include "klibc.h"
|
|
||||||
#include "kthread.h"
|
|
||||||
#include "vga.h"
|
|
||||||
#define STR_HELPER(x) #x
|
|
||||||
#define STR(x) STR_HELPER(x)
|
|
||||||
|
|
||||||
// Need GCC > 6
|
|
||||||
#define DEFINE_INTERRUPT(int_nb) \
|
|
||||||
__attribute__((interrupt)) void print_handler_##int_nb(struct interrupt_frame *frame, \
|
|
||||||
ulong error_code) \
|
|
||||||
{ \
|
|
||||||
int intNbInt = int_nb; \
|
|
||||||
VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "EXCEPTION %d %d", intNbInt, error_code); \
|
|
||||||
printf("Exception %d (Err %d) at 0x%x\n", int_nb, error_code, frame->eip); \
|
|
||||||
asm("hlt"); \
|
|
||||||
}
|
|
||||||
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_DOUBLE_FAULT)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_DIVIDE_ZERO)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_DEBUG)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_NMI)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_BREAKPOINT)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_OVERFLOW)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_BOUND_RANGE_EXCEEDED)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_INVALID_OPCODE)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_DEVICE_NOT_AVAILABLE)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_COPRO_OVERRUN)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_INVALID_TSS)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_SEGMENT_NOT_PRESENT)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_STACK_SEGMENT_FAULT)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_GENERAL_PROTECTION_FAULT)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_PAGE_FAULT)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_RESERVED_1)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_X87_FP_EXCEPTION)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_ALIGNMENT_CHECK)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_MACHINE_CHECK)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_SIMD_FP)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_VIRTUALIZATION)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_RESERVED_2)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_RESERVED_3)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_RESERVED_4)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_RESERVED_5)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_RESERVED_6)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_RESERVED_7)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_RESERVED_8)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_RESERVED_9)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_RESERVED_10)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_SECURITY)
|
|
||||||
DEFINE_INTERRUPT(EXCEPTION_RESERVED_11)
|
|
||||||
// c.f. https://wiki.osdev.org/Paging#Handling
|
|
||||||
// error_code bit0: Present ?
|
|
||||||
// bit1: Trying to write ?
|
|
||||||
// bit2: User page try to access?
|
|
||||||
__attribute__((interrupt)) void pagefault_handler(struct interrupt_frame *frame,
|
|
||||||
ulong error_code)
|
|
||||||
{
|
|
||||||
// A page fault has occurred.
|
|
||||||
// The faulting address is stored in the CR2 register.
|
|
||||||
uint32_t faulting_address;
|
|
||||||
asm volatile("mov %%cr2, %0" : "=r"(faulting_address));
|
|
||||||
|
|
||||||
struct kthread *current = getCurrentThread();
|
|
||||||
printf("page fault while in thread %s at 0x%x\n", current->name, faulting_address);
|
|
||||||
VGAPrintf(RED, BLACK, 0, VGA_HEIGHT - 1, "PAGE FAULT %d", error_code);
|
|
||||||
(void)faulting_address;
|
|
||||||
(void)frame;
|
|
||||||
(void)error_code;
|
|
||||||
for(;;)
|
|
||||||
continue;
|
|
||||||
}
|
|
84
arch/x86/exception_wrappers.S
Normal file
84
arch/x86/exception_wrappers.S
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#define ASM_SOURCE 1
|
||||||
|
.file "irq_wrappers.S"
|
||||||
|
.text
|
||||||
|
|
||||||
|
.extern exception_handler_wrap
|
||||||
|
.globl exception_handler_wrapper_array
|
||||||
|
|
||||||
|
.altmacro
|
||||||
|
|
||||||
|
|
||||||
|
.macro exception_mac id
|
||||||
|
exception_wrapper_\id:
|
||||||
|
.type exception_wrapper_\id,@function
|
||||||
|
/* INTERRUPT FRAME START */
|
||||||
|
/* ALREADY PUSHED TO US BY THE PROCESSOR UPON ENTRY TO THIS INTERRUPT */
|
||||||
|
/* uint32_t ip */
|
||||||
|
/* uint32_t cs; */
|
||||||
|
/* uint32_t flags */
|
||||||
|
/* Pushes the other reg to save same and look like a struct cpu_state*/
|
||||||
|
/* Fake error code */
|
||||||
|
pushl $0
|
||||||
|
|
||||||
|
/* Backup the actual context */
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
pushl %edx
|
||||||
|
pushl %ecx
|
||||||
|
pushl %ebx
|
||||||
|
pushl %eax
|
||||||
|
subl $2,%esp
|
||||||
|
pushw %ss
|
||||||
|
pushw %ds
|
||||||
|
pushw %es
|
||||||
|
pushw %fs
|
||||||
|
pushw %gs
|
||||||
|
|
||||||
|
push %esp
|
||||||
|
pushl $\id
|
||||||
|
call exception_handler_wrap
|
||||||
|
addl $8, %esp
|
||||||
|
|
||||||
|
/* Restore the context */
|
||||||
|
popw %gs
|
||||||
|
popw %fs
|
||||||
|
popw %es
|
||||||
|
popw %ds
|
||||||
|
popw %ss
|
||||||
|
addl $2,%esp
|
||||||
|
popl %eax
|
||||||
|
popl %ebx
|
||||||
|
popl %ecx
|
||||||
|
popl %edx
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebp
|
||||||
|
|
||||||
|
/* Remove fake error code */
|
||||||
|
addl $4, %esp
|
||||||
|
|
||||||
|
iret
|
||||||
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
.set i, 0
|
||||||
|
.rept 0x20
|
||||||
|
exception_mac %i
|
||||||
|
.set i, i+1
|
||||||
|
.endr
|
||||||
|
|
||||||
|
.macro ref_exception_wrapper id
|
||||||
|
.long exception_wrapper_\id
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.section ".rodata"
|
||||||
|
.p2align 5, 0x0
|
||||||
|
exception_handler_wrapper_array:
|
||||||
|
.set i, 0x0
|
||||||
|
.rept 0x20
|
||||||
|
ref_exception_wrapper %i
|
||||||
|
.set i, i+1
|
||||||
|
.endr
|
@ -1,57 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "stdarg.h"
|
#include "stdarg.h"
|
||||||
|
#include "cpu_context.h"
|
||||||
|
|
||||||
// c.f. intel software-developer-vol-1 6.4.1
|
// c.f. intel software-developer-vol-1 6.4.1
|
||||||
struct interrupt_frame {
|
struct interrupt_frame {
|
||||||
|
/* Stacked by the CPU */
|
||||||
uint32_t eip;
|
uint32_t eip;
|
||||||
uint32_t cs;
|
uint32_t cs;
|
||||||
uint32_t eflags;
|
uint32_t eflags;
|
||||||
uint32_t esp;
|
} __attribute__((packed));
|
||||||
uint32_t ss;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Exception
|
|
||||||
#define DECLARE_INTERRUPT(int_nb) \
|
|
||||||
void print_handler_##int_nb(struct interrupt_frame *frame, ulong error_code);
|
|
||||||
|
|
||||||
#define ACCESS_INTERRUPT(int_nb) print_handler_##int_nb
|
|
||||||
|
|
||||||
void pagefault_handler(struct interrupt_frame *frame, ulong error_code);
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_DOUBLE_FAULT)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_DIVIDE_ZERO)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_DEBUG)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_NMI)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_BREAKPOINT)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_OVERFLOW)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_BOUND_RANGE_EXCEEDED)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_INVALID_OPCODE)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_DEVICE_NOT_AVAILABLE)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_COPRO_OVERRUN)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_INVALID_TSS)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_SEGMENT_NOT_PRESENT)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_STACK_SEGMENT_FAULT)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_GENERAL_PROTECTION_FAULT)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_PAGE_FAULT)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_RESERVED_1)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_X87_FP_EXCEPTION)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_ALIGNMENT_CHECK)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_MACHINE_CHECK)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_SIMD_FP)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_VIRTUALIZATION)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_RESERVED_2)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_RESERVED_3)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_RESERVED_4)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_RESERVED_5)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_RESERVED_6)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_RESERVED_7)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_RESERVED_8)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_RESERVED_9)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_RESERVED_10)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_SECURITY)
|
|
||||||
DECLARE_INTERRUPT(EXCEPTION_RESERVED_11)
|
|
||||||
|
|
||||||
// IRQ
|
// IRQ
|
||||||
void pit_handler(struct interrupt_frame *frame);
|
void pit_handler(struct interrupt_frame *frame);
|
||||||
void keyboard_handler(struct interrupt_frame *frame);
|
|
||||||
void timer_handler(struct interrupt_frame *frame);
|
|
||||||
void serial_handler(struct interrupt_frame *frame);
|
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
#include "irq.h"
|
#include "irq.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "klibc.h"
|
||||||
#include "pic.h"
|
#include "pic.h"
|
||||||
#include "stdarg.h"
|
#include "stdarg.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
int irqSetup()
|
int irqSetup()
|
||||||
{
|
{
|
||||||
@ -9,11 +12,47 @@ int irqSetup()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Assembly defined array. This is used to wrap C function than cannot:
|
||||||
|
// * get some cpu state
|
||||||
|
// * return using "iret" instead of "ret" without some compiler __attribute__
|
||||||
|
extern native_irq_handler irq_handler_wrapper_array[IRQ_NUM];
|
||||||
|
|
||||||
irq_handler irq_handler_array[IRQ_NUM] = {
|
irq_handler irq_handler_array[IRQ_NUM] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
int irqSetRoutine(int irq, irq_handler handler)
|
void interrupt_handler_pic(int interrupt, struct cpu_state *frame)
|
||||||
|
{
|
||||||
|
if (0 > interrupt || IRQ_NUM <= interrupt) {
|
||||||
|
pr_err("Trying to handle unknow interrupt %d\n", interrupt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
EOIIrq(interrupt);
|
||||||
|
|
||||||
|
if (irq_handler_array[interrupt] != NULL)
|
||||||
|
irq_handler_array[interrupt](frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
int irqSetRoutine(int irq, native_irq_handler handler)
|
||||||
|
{
|
||||||
|
uint32_t flags;
|
||||||
|
if ((irq < 0) || irq >= IRQ_NUM)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
disable_IRQs(flags);
|
||||||
|
|
||||||
|
if (handler != NULL) {
|
||||||
|
int ret = idt_set_handler(IRQ_INTERRUPT_BASE_ADDRESS + irq,
|
||||||
|
(unsigned int)handler, 0);
|
||||||
|
if (!ret)
|
||||||
|
enableIrq(irq);
|
||||||
|
}
|
||||||
|
restore_IRQs(flags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int irqSetRoutineWrapped(int irq, irq_handler handler)
|
||||||
{
|
{
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
if ((irq < 0) || irq >= IRQ_NUM)
|
if ((irq < 0) || irq >= IRQ_NUM)
|
||||||
@ -25,7 +64,7 @@ int irqSetRoutine(int irq, irq_handler handler)
|
|||||||
|
|
||||||
if (handler != NULL) {
|
if (handler != NULL) {
|
||||||
int ret = idt_set_handler(IRQ_INTERRUPT_BASE_ADDRESS + irq,
|
int ret = idt_set_handler(IRQ_INTERRUPT_BASE_ADDRESS + irq,
|
||||||
(unsigned int)irq_handler_array[irq], 0);
|
(unsigned int)irq_handler_wrapper_array[irq], 0);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
enableIrq(irq);
|
enableIrq(irq);
|
||||||
}
|
}
|
||||||
|
@ -35,6 +35,10 @@
|
|||||||
// https://wiki.osdev.org/Interrupt_Service_Routines That's why we use wrapper around them or
|
// https://wiki.osdev.org/Interrupt_Service_Routines That's why we use wrapper around them or
|
||||||
// the gcc interrupt attribut
|
// the gcc interrupt attribut
|
||||||
// __attribute__((interrupt)) void (*irq_handler)(int irq);
|
// __attribute__((interrupt)) void (*irq_handler)(int irq);
|
||||||
typedef void (*irq_handler)(struct interrupt_frame *frame);
|
typedef void (*irq_handler)(struct cpu_state *frame);
|
||||||
|
typedef void (*native_irq_handler)(struct interrupt_frame *frame);
|
||||||
int irqSetup();
|
int irqSetup();
|
||||||
int irqSetRoutine(int irq, irq_handler handler);
|
// For C coded handler (The interrupt specific part is managed by a wrapper)
|
||||||
|
int irqSetRoutineWrapped(int irq, irq_handler handler);
|
||||||
|
// For ASM handler taking care of the special instruction needed by an IRQ handler
|
||||||
|
int irqSetRoutine(int irq, native_irq_handler handler);
|
||||||
|
@ -1,29 +0,0 @@
|
|||||||
#include "interrupt.h"
|
|
||||||
#include "io.h"
|
|
||||||
#include "irq.h"
|
|
||||||
#include "keyboard.h"
|
|
||||||
#include "pic.h"
|
|
||||||
#include "serial.h"
|
|
||||||
#include "vga.h"
|
|
||||||
|
|
||||||
// Need GCC > 6
|
|
||||||
__attribute__((interrupt)) void keyboard_handler(struct interrupt_frame *frame)
|
|
||||||
{
|
|
||||||
EOIIrq(IRQ_KEYBOARD);
|
|
||||||
keyboard_do_irq();
|
|
||||||
(void)frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((interrupt)) void timer_handler(struct interrupt_frame *frame)
|
|
||||||
{
|
|
||||||
static int timeCnt = 0;
|
|
||||||
EOIIrq(IRQ_TIMER);
|
|
||||||
VGAPrintf(RED, BLACK, 20, VGA_HEIGHT - 1, "IRQ %d", timeCnt++);
|
|
||||||
(void)frame;
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__((interrupt)) void serial_handler(struct interrupt_frame *frame)
|
|
||||||
{
|
|
||||||
EOIIrq(IRQ_COM1);
|
|
||||||
serialDoIrq(frame);
|
|
||||||
}
|
|
84
arch/x86/irq_wrappers.S
Normal file
84
arch/x86/irq_wrappers.S
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#define ASM_SOURCE 1
|
||||||
|
.file "irq_wrappers.S"
|
||||||
|
.text
|
||||||
|
|
||||||
|
.extern interrupt_handler_pic
|
||||||
|
.globl irq_handler_wrapper_array
|
||||||
|
|
||||||
|
.altmacro
|
||||||
|
|
||||||
|
|
||||||
|
.macro interrupt_pic irq
|
||||||
|
int_wrapper_\irq:
|
||||||
|
.type int_wrapper_\irq,@function
|
||||||
|
/* INTERRUPT FRAME START */
|
||||||
|
/* ALREADY PUSHED TO US BY THE PROCESSOR UPON ENTRY TO THIS INTERRUPT */
|
||||||
|
/* uint32_t ip */
|
||||||
|
/* uint32_t cs; */
|
||||||
|
/* uint32_t flags */
|
||||||
|
/* Pushes the other reg to save same and look like a struct cpu_state*/
|
||||||
|
/* Fake error code */
|
||||||
|
pushl $0
|
||||||
|
|
||||||
|
/* Backup the actual context */
|
||||||
|
pushl %ebp
|
||||||
|
movl %esp, %ebp
|
||||||
|
|
||||||
|
pushl %edi
|
||||||
|
pushl %esi
|
||||||
|
pushl %edx
|
||||||
|
pushl %ecx
|
||||||
|
pushl %ebx
|
||||||
|
pushl %eax
|
||||||
|
subl $2,%esp
|
||||||
|
pushw %ss
|
||||||
|
pushw %ds
|
||||||
|
pushw %es
|
||||||
|
pushw %fs
|
||||||
|
pushw %gs
|
||||||
|
|
||||||
|
push %esp
|
||||||
|
pushl $\irq
|
||||||
|
call interrupt_handler_pic
|
||||||
|
addl $8, %esp
|
||||||
|
|
||||||
|
/* Restore the context */
|
||||||
|
popw %gs
|
||||||
|
popw %fs
|
||||||
|
popw %es
|
||||||
|
popw %ds
|
||||||
|
popw %ss
|
||||||
|
addl $2,%esp
|
||||||
|
popl %eax
|
||||||
|
popl %ebx
|
||||||
|
popl %ecx
|
||||||
|
popl %edx
|
||||||
|
popl %esi
|
||||||
|
popl %edi
|
||||||
|
popl %ebp
|
||||||
|
|
||||||
|
/* Remove fake error code */
|
||||||
|
addl $4, %esp
|
||||||
|
|
||||||
|
iret
|
||||||
|
.endm
|
||||||
|
|
||||||
|
|
||||||
|
.set i, 0
|
||||||
|
.rept 0x10
|
||||||
|
interrupt_pic %i
|
||||||
|
.set i, i+1
|
||||||
|
.endr
|
||||||
|
|
||||||
|
.macro ref_int_wrapper irq
|
||||||
|
.long int_wrapper_\irq
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.section ".rodata"
|
||||||
|
.p2align 5, 0x0
|
||||||
|
irq_handler_wrapper_array:
|
||||||
|
.set i, 0x0
|
||||||
|
.rept 0x10
|
||||||
|
ref_int_wrapper %i
|
||||||
|
.set i, i+1
|
||||||
|
.endr
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "assert.h"
|
||||||
#include "stdarg.h"
|
#include "stdarg.h"
|
||||||
#include "minmax.h"
|
#include "minmax.h"
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "interrupt.h"
|
#include "interrupt.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "irq.h"
|
#include "irq.h"
|
||||||
|
#include "keyboard.h"
|
||||||
#include "klibc.h"
|
#include "klibc.h"
|
||||||
#include "kthread.h"
|
#include "kthread.h"
|
||||||
#include "mem.h"
|
#include "mem.h"
|
||||||
@ -134,7 +135,7 @@ void kmain(unsigned long magic, unsigned long addr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
printf("Setting up IRQ handlers\n");
|
printf("Setting up IRQ handlers\n");
|
||||||
irqSetRoutine(IRQ_KEYBOARD, keyboard_handler);
|
irqSetRoutineWrapped(IRQ_KEYBOARD, keyboard_do_irq);
|
||||||
|
|
||||||
printf("Enabling HW interrupts\n");
|
printf("Enabling HW interrupts\n");
|
||||||
// Enabling the HW interrupts
|
// Enabling the HW interrupts
|
||||||
|
@ -42,7 +42,7 @@ void initPic(void)
|
|||||||
outb(PIC_SLAVE_DATA, 0xFF);
|
outb(PIC_SLAVE_DATA, 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EOIIrq(int irq)
|
inline void EOIIrq(int irq)
|
||||||
{
|
{
|
||||||
if (irq >= 8)
|
if (irq >= 8)
|
||||||
outb(PIC_SLAVE_CMD, PIC_EOI);
|
outb(PIC_SLAVE_CMD, PIC_EOI);
|
||||||
|
@ -32,7 +32,7 @@ void serialSetup(int speed)
|
|||||||
UART_1_STOP_BIT); // 8 bits, no parity, one stop bit
|
UART_1_STOP_BIT); // 8 bits, no parity, one stop bit
|
||||||
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
outb(PORT + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
|
||||||
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
outb(PORT + 4, 0x0B); // IRQs enabled, RTS/DSR set
|
||||||
irqSetRoutine(IRQ_COM1, serial_handler);
|
irqSetRoutineWrapped(IRQ_COM1, serialDoIrq);
|
||||||
}
|
}
|
||||||
|
|
||||||
int isTransmitEmpty()
|
int isTransmitEmpty()
|
||||||
@ -48,9 +48,9 @@ void serialPutc(char a)
|
|||||||
outb(PORT, a);
|
outb(PORT, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
void serialDoIrq(struct interrupt_frame *level)
|
void serialDoIrq(struct cpu_state *state)
|
||||||
{
|
{
|
||||||
(void)level;
|
(void)state;
|
||||||
char c = inb(PORT);
|
char c = inb(PORT);
|
||||||
serialPutc(c);
|
serialPutc(c);
|
||||||
}
|
}
|
||||||
|
@ -3,4 +3,4 @@
|
|||||||
|
|
||||||
void serialSetup(int speed);
|
void serialSetup(int speed);
|
||||||
void serialPutc(char a);
|
void serialPutc(char a);
|
||||||
void serialDoIrq(struct interrupt_frame *frame);
|
void serialDoIrq(struct cpu_state *state);
|
||||||
|
Loading…
Reference in New Issue
Block a user