Mon, 08 Jan 2018 16:53:42 +0100
10 files changed,
110 insertions(+),
26 deletions(-)
M
include/assembly.h
→
include/assembly.h
@@ -48,6 +48,34 @@ __asm__ volatile ("sti");
} /*! + * Pushes the contents of the EFLAGS register onto the stack. + */ +__attribute__((always_inline)) inline void pushf(void) { + __asm__ volatile ("pushf"); +} + +/*! + * Pops the contents of the EFLAGS register from the top of the stack. + */ +__attribute__((always_inline)) inline void popf(void) { + __asm__ volatile ("popf"); +} + +/*! + * Pushes the contents of the general purpose registers onto the stack. + */ +__attribute__((always_inline)) inline void pusha(void) { + __asm__ volatile ("pusha"); +} + +/*! + * Pops the contents of the general purpose registers off the top of the stack. + */ +__attribute__((always_inline)) inline void popa(void) { + __asm__ volatile ("popa"); +} + +/*! * CPUID */ __attribute__((always_inline)) inline void cpuid(uint32_t eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) {
M
include/cedos/interrupts.h
→
include/cedos/interrupts.h
@@ -7,8 +7,14 @@ #define OS_INTERRUPTS_H
#include <stdint.h> -#define INTERRUPT(name, frame) __attribute__((interrupt)) void name(INTERRUPT_FRAME *frame) -#define EXCEPTION(name, frame, err_code) __attribute__((interrupt)) void name(INTERRUPT_FRAME *frame, uword_t err_code) +#define INTERRUPT(name, frame) __attribute__((interrupt, optimize("O0"))) void name(INTERRUPT_FRAME *frame) +#define EXCEPTION(name, frame, err_code) __attribute__((interrupt, optimize("O0"))) void name(INTERRUPT_FRAME *frame, uword_t err_code) + +#define INT_GATE (0b10001110) +#define TRAP_GATE (0b10001111) +#define SYSCALL_INTERRUPT (0b11101110) + +#define INTERRUPT_COUNT 0x31 /*! * Represents a single entry of the IDT.@@ -30,5 +36,6 @@
typedef uint32_t uword_t; int interrupts_init(void); +void install_interrupt(int num, void* func, uint16_t selector, uint8_t type); #endif
M
include/cedos/pic.h
→
include/cedos/pic.h
@@ -39,11 +39,11 @@
/*! * Sends an end-of-interrupt-signal to the corresponding PIC. */ -inline void pic1_eoi(void) { +__attribute__((always_inline)) inline void pic1_eoi(void) { outb(PIC_END_OF_INTERRUPT, PIC1_COMMAND); } -inline void pic2_eoi(void) { +__attribute__((always_inline)) inline void pic2_eoi(void) { outb(PIC_END_OF_INTERRUPT, PIC2_COMMAND); outb(PIC_END_OF_INTERRUPT, PIC1_COMMAND); }
M
include/cedos/pit.h
→
include/cedos/pit.h
@@ -36,4 +36,6 @@ * \param freq_div Desired frequency divider.
*/ void pit_setup_channel(PIT_CHANNEL channel, PIT_MODE mode, uint16_t freq_div); +void pit_init(void); + #endif
M
include/cedos/scheduler.h
→
include/cedos/scheduler.h
@@ -19,4 +19,9 @@ * Initializes the scheduler.
*/ int sched_init(void); +/*! + * Starts the scheduler. + */ +int sched_start(void); + #endif
M
kernel/interrupts.c
→
kernel/interrupts.c
@@ -1,10 +1,8 @@
#include "cedos/interrupts.h" #include "cedos/drivers/console.h" #include "cedos/pic.h" - -#define INT_GATE (0b10001110) -#define TRAP_GATE (0b10001111) -#define SYSCALL_INTERRUPT (0b11101110) +#include "cedos/core.h" +#include "cedos/pit.h" #define array_sizeof(array) (sizeof(array)/sizeof(array[0]))@@ -50,14 +48,15 @@ printk("PIC2 INTERRUPT\n");
pic2_eoi(); } -IDT_ENTRY IDT[31]; +IDT_ENTRY IDT[INTERRUPT_COUNT]; +void (*INT_HANDLERS[INTERRUPT_COUNT])(void); -void install_interrupt(int index, void* func, uint16_t selector, uint8_t type) { - IDT[index].offset_0 = (uint16_t)((uint32_t)func); - IDT[index].selector = selector; - IDT[index].__zero = 0; - IDT[index].type_attr = type; - IDT[index].offset_16 = (uint16_t)((uint32_t)(func) >> 16); +void install_interrupt(int num, void* func, uint16_t selector, uint8_t type) { + IDT[num].offset_0 = (uint16_t)((uint32_t)func); + IDT[num].selector = selector; + IDT[num].__zero = 0; + IDT[num].type_attr = type; + IDT[num].offset_16 = (uint16_t)((uint32_t)(func) >> 16); } struct {@@ -69,7 +68,7 @@ IDT
}; int interrupts_init(void) { - for (uint32_t i = 0; i < array_sizeof(IDT); i++) { + for (uint32_t i = 0; i < INTERRUPT_COUNT; i++) { if (i == 0x03) { install_interrupt(i, breakpoint_isr, 0x08, INT_GATE); } else if (i == 0x08) {
M
kernel/main.c
→
kernel/main.c
@@ -1,6 +1,7 @@
#include "cedos/drivers/console.h" #include "cedos/interrupts.h" #include "cedos/pic.h" +#include "cedos/pit.h" #include "cedos/scheduler.h" #include "cedos/mm/paging.h" #include "cedos/core.h"@@ -12,13 +13,17 @@ printk("Core functions initialized.\n");
printk("Initializing PIC..."); pic_init(); + printk("done.\n"); + + printk("Initializing PIT..."); + pit_init(); printk("done.\n"); printk("Initializing interrupts..."); interrupts_init(); printk("done.\n"); - printk("Activating interrupts..."); + printk("Setting up timer interrupts..."); sti(); printk("done.\n");@@ -37,13 +42,19 @@ cpuid(0, &res[0], &res[2], &res[1]);
res[3] = 0; printk("CPU manufacturer: %s\n", res); } + +extern uint8_t* IDT; int os_main(void) { + //pic_unmask_interrupt(0); infodump(); - kpanic("SIMULATED KERNEL PANIC"); + printk("Starting scheduler."); + sched_start(); + + //kpanic("SIMULATED KERNEL PANIC"); // won't be executed - printk("Main procedure terminating.\n"); + //printk("Main procedure terminating.\n"); return 0; }
M
kernel/pic.c
→
kernel/pic.c
@@ -27,7 +27,7 @@ outb(0x01, PIC1_DATA);
outb(0x01, PIC2_DATA); nop(); nop(); nop(); nop(); - // clear interrupt masks + // mask all interrupts outb(0xff, PIC1_DATA); outb(0xff, PIC2_DATA);@@ -42,7 +42,7 @@ */
int pic_unmask_interrupt(int irq) { uint16_t port; - if (irq >= 8) { + if (irq < 8) { port = PIC1_DATA; } else { port = PIC2_DATA;@@ -64,7 +64,7 @@ */
int pic_mask_interrupt(int irq) { uint16_t port; - if (irq >= 8) { + if (irq < 8) { port = PIC1_DATA; } else { port = PIC2_DATA;
M
kernel/pit.c
→
kernel/pit.c
@@ -1,10 +1,12 @@
#include "cedos/pit.h" #include "assembly.h" +#include "cedos/pic.h" #define PIT_ACCESS_MODE_LO_HI (0b11 << 4) #define PIT_COMMAND_PORT ((uint16_t)0x43) void pit_setup_channel(PIT_CHANNEL channel, PIT_MODE mode, uint16_t freq_div) { + pushf(); cli(); outb(((uint8_t)channel << 6) | PIT_ACCESS_MODE_LO_HI | (uint8_t)mode, PIT_COMMAND_PORT); nop(); nop(); nop(); nop();@@ -13,5 +15,10 @@ outb((uint8_t)(freq_div & 0xFF), 0x40 + (uint16_t)channel);
nop(); nop(); nop(); nop(); outb((uint8_t)(freq_div >> 8), 0x40 + (uint16_t)channel); - sti(); + popf(); +} + +void pit_init(void) { + pic_unmask_interrupt(0); + return 1; }
M
kernel/scheduler.c
→
kernel/scheduler.c
@@ -3,6 +3,11 @@ #include "cedos/process.h"
#include "cedos/mm/paging.h" #include "cedos/drivers/console.h" #include "cedos/core.h" +#include "cedos/interrupts.h" +#include "cedos/pit.h" +#include "cedos/pic.h" +#include "assembly.h" +#include "cedos/drivers/speaker.h" PROCESS* get_slot(void) { static PROCESS free_slots[4];@@ -27,17 +32,37 @@
return add_process(p); } +INTERRUPT(sched_interrupt, frame) { + printk("--#"); + + // reset the timer + pit_setup_channel(PIT_CHANNEL_0, PIT_MODE_0, 0xFFFF); + + uint32_t big_ben[] = { 415, 330, 370, 247, 247, 370, 415, 330 }; + static int i = 0; + + bios_sp.make_sound(big_ben[(i / 8) % (sizeof(big_ben)/sizeof(big_ben[0]))], 1); + i++; + + pic1_eoi(); +} + int sched_init(void) { // TODO: create and start idle process //sched_exec(create_empty_page_dir(), (void*)0, (void*)0); + + // install timer interrupt + install_interrupt(0x20, sched_interrupt, 0x08, INT_GATE); + return 1; } -int sched_dispatcher(void) { - +int sched_start(void) { + // perform the first timer interrupt manually + INT(0x20); } -INTERRUPT(sched_interrupt, frame) { +int sched_dispatcher(void) { }