CeDOS - Commit 2a664053

DON'T INTERRUPT ME Interrupts are implemented, code now requires GCC version 7 or higher. Had to add a hack to make new linker work; bss segment is needed separately for whatever reason. Execution hits a double fault, but that is to be expected - we haven't yet setup the PIC, so the 0x08-interrupt will be fired by a misaligned PIC interrupt
Celina Sophie Kalus
Wed, 27 Dec 2017 00:51:39 +0100
6 files changed, 110 insertions(+), 9 deletions(-)
M README.mdREADME.md

@@ -3,7 +3,7 @@ Simple x86 operating system written in assembly and C.

## Software Requirements * GNU make -* Cross-Compiler + binutils: gcc build for freestanding target i386-elf. If a prefix is needed, set the corresponding variable in the makefile. +* GCC 7 (or higher) Cross Compiler + matching binutils, tailored for freestanding i686-elf-targets * Doxygen: If you want to build the documentation ## Make commands
M kernel/os_interrupts.ckernel/os_interrupts.c

@@ -0,0 +1,72 @@

+#include "os_interrupts.h" +#include "os_text.h" + +#define HARDWARE_INTERRUPT (0b10001110) +#define SYSCALL_INTERRUPT (0b11101110) + +#define array_sizeof(array) (sizeof(array)/sizeof(array[0])) + +#define MAKE_IDT_ENTRY(func, selector, type) { \ + (uint16_t)(func), \ + (uint16_t)(selector), \ + 0, \ + (uint8_t)(type), \ + (uint16_t)(0xC000) \ + } + +struct interrupt_frame { + +}; + +__attribute__((interrupt)) void default_isr(struct interrupt_frame *frame) { + write("interrupt was issued\n"); +} + +__attribute__((interrupt)) void breakpoint_isr(struct interrupt_frame *frame) { + write("BREAKPOINT WAS HIT\n"); + // dump registers to stdout +} + +__attribute__((interrupt)) void double_fault_isr(struct interrupt_frame *frame) { + write("CRITICAL: DOUBLE FAULT\n"); + while (1) {} +} + +IDT_ENTRY IDT[31]; + +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); + //if (index == 7) { while(1) {} } +} + +struct { + uint16_t limit; + void* offset; +}__attribute__((packed)) IDT_DESC = { + sizeof(IDT), + IDT +}; + +void init_interrupts(void) { + for (uint32_t i = 0; i < array_sizeof(IDT); i++) { + switch (i) { + case 0x03: + install_interrupt(i, breakpoint_isr, 0x08, HARDWARE_INTERRUPT); + case 0x08: + install_interrupt(i, double_fault_isr, 0x08, HARDWARE_INTERRUPT); + break; + default: + install_interrupt(i, default_isr, 0x08, HARDWARE_INTERRUPT); + } + } + + __asm__ volatile ( + "lidt (%0)\n" + "sti" : : + "m" (IDT_DESC) + ); +}
M kernel/os_interrupts.hkernel/os_interrupts.h

@@ -1,4 +1,23 @@

/*! \file * Sets up the interrupt descriptor table and provides functions to * hook functions to interrupts. - */+ */ +#ifndef OS_INTERRUPTS_H +#define OS_INTERRUPTS_H + + #include <stdint.h> + +/*! + * Represents a single entry of the IDT. + */ +typedef struct { + uint16_t offset_0; + uint16_t selector; + uint8_t __zero; + uint8_t type_attr; + uint16_t offset_16; +}__attribute__((packed)) IDT_ENTRY; + +void init_interrupts(void); + +#endif
M kernel/os_main.ckernel/os_main.c

@@ -1,6 +1,9 @@

#include "os_text.h" +#include "os_interrupts.h" int main(void) { + init_interrupts(); + const char* string[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; clear(); for (int i = 0; i < 50; i++) {
M link.txtlink.txt

@@ -1,5 +1,5 @@

-OUTPUT_FORMAT(binary) OUTPUT_ARCH(i386) +OUTPUT_FORMAT(elf32-i386) PAGE_SIZE = 1 << 12;

@@ -29,12 +29,18 @@

KERNEL : AT(LOADADDR(SECOND_STAGE) + SIZEOF(SECOND_STAGE)) { */kernel.o(.*) + */kernel.o(.bss) } >KERNEL APPLICATION : AT(LOADADDR(KERNEL) + SIZEOF(KERNEL)) { + + } >APPLICATION - } >APPLICATION + .bss : AT(LOADADDR(APPLICATION) + SIZEOF(APPLICATION)) + { + + } >KERNEL } __SS_LMA = LOADADDR(SECOND_STAGE);
M makefilemakefile

@@ -4,14 +4,14 @@ export CURRENT_DIR = $(shell pwd)

export INCLUDE_DIR = $(CURRENT_DIR)/include export DEBUG_DIR = $(CURRENT_DIR)/debug -export GCC_PREFIX = $(HOME)/opt/cross/i686-elf-/bin/i686-elf- +export GCC_PREFIX = $(HOME)/opt/cross/bin/i686-elf- ifdef DEBUG GLOBAL_BUILD = $(CURRENT_DIR)/build/debug -GCC_OPTIONS = -D DEBUG -O0 -Wno-write-strings -Qn -Wall -Wextra -fno-exceptions -nostdlib -nostartfiles -ffreestanding +GCC_OPTIONS = -D DEBUG -g -O0 -Wno-write-strings -Qn -Wall -Wextra -fno-exceptions -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only else GLOBAL_BUILD = $(CURRENT_DIR)/build/release -GCC_OPTIONS = -O1 -Wno-write-strings -Qn -Wall -Wextra -fno-exceptions -nostdlib -nostartfiles -ffreestanding +GCC_OPTIONS = -O1 -Wno-write-strings -Qn -Wall -Wextra -fno-exceptions -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only endif export GLOBAL_BUILD

@@ -26,8 +26,9 @@ > @mkdir $(GLOBAL_BUILD)/kernel 2> /dev/null; true

> $(MAKE) LOCAL_BUILD=$(GLOBAL_BUILD)/boot -C boot build > $(MAKE) LOCAL_BUILD=$(GLOBAL_BUILD)/second_stage -C second_stage build > $(MAKE) LOCAL_BUILD=$(GLOBAL_BUILD)/kernel -C kernel build -> $(GCC_PREFIX)ld $(wildcard $(GLOBAL_BUILD)/*.o) -T link.txt -Map=$(DEBUG_DIR)/mapfile.txt -o $(GLOBAL_BUILD)/base.img --oformat binary -> @cp $(GLOBAL_BUILD)/base.img $(CURRENT_DIR)/build 2> /dev/null; true +> $(GCC_PREFIX)ld $(wildcard $(GLOBAL_BUILD)/*.o) -T link.txt -Map=$(DEBUG_DIR)/mapfile.txt -o build/base.o +> $(GCC_PREFIX)objcopy --only-keep-debug build/base.o $(DEBUG_DIR)/base.sym +> $(GCC_PREFIX)objcopy -O binary build/base.o build/base.img .PHONY: clear clear: