CeDOS - Commit 9507c51a

blahblah
Celina Sophie Kalus
Thu, 04 Jan 2018 21:22:08 +0100
21 files changed, 459 insertions(+), 68 deletions(-)
M boot/stage2/main.cboot/stage2/main.c

@@ -1,6 +1,7 @@

#include "linker.h" #include "paging.h" +/* #define VGA_TEXTMODE_COLUMNS 80 #define VGA_TEXTMODE_LINES 25 #define VGA_TEXTMODE_CELLS (VGA_TEXTMODE_COLUMNS * VGA_TEXTMODE_LINES)

@@ -34,17 +35,13 @@ display++;

display++; } } +*/ void copy_kernel(void) { - simple_clear(); - simple_print("COPYING_KERNEL..."); - uint8_t *kernel_dest = (uint8_t*)0x00100000; uint8_t *kernel_src = (SS_VMA + (KERNEL_LMA - SS_LMA)); for (uint32_t i = 0; i < KERNEL_SIZE; i++) { kernel_dest[i] = kernel_src[i]; } - - simple_println("DONE."); }
M include/assembly.hinclude/assembly.h

@@ -34,8 +34,35 @@ __asm__ volatile ("nop");

} /*! + * Deactivates all interrupts. + */ +__attribute__((always_inline)) inline void cli(void) { + __asm__ volatile ("cli"); +} + +/*! + * Reactivates all interrupts. + */ +__attribute__((always_inline)) inline void sti(void) { + __asm__ volatile ("sti"); +} + +/*! + * CPUID + */ +__attribute__((always_inline)) inline void cpuid(uint32_t eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { + __asm__ volatile ( "mov %3, %%eax;" + "cpuid;" + "mov %%ebx, %0;" + "mov %%ecx, %1;" + "mov %%edx, %2" + : "=m" (*ebx), "=m" (*ecx), "=m" (*edx) + : "Nd" (eax)); +} + +/*! * Causes an interrupt */ -#define int(n) __asm__ volatile ("int $" #n) +#define INT(n) __asm__ volatile ("int $" #n) #endif
A include/assert.h

@@ -0,0 +1,8 @@

+#ifndef ASSERT_H +#define ASSERT_H + +#include <stdint.h> + +#define assert(cond) if (!(cond)) { kpanic("Assertion failed: " #cond); } + +#endif
A include/cedos/core.h

@@ -0,0 +1,16 @@

+/*! + * Defines important kernel mode functions + */ +#ifndef KERNEL_H +#define KERNEL_H + +#include <stdarg.h> + +#include "cedos/drivers/console.h" + +int core_init(void); +void printk(const char* string, ...); +void kpanic(const char* string); +void memdump(void* start, uint32_t size); + +#endif
M include/cedos/drivers/console.hinclude/cedos/drivers/console.h

@@ -1,8 +1,8 @@

/*! \file - * Driver for VGA textmode output + * Driver for consoles. */ -#ifndef TEXT_H -#define TEXT_H +#ifndef CONSOLE_H +#define CONSOLE_H #include <stdint.h>

@@ -47,5 +47,7 @@ } CON_DRIVER;

//! VGA console driver (default driver) CON_DRIVER vga_con; + +CON_DRIVER *std_con; #endif
M include/cedos/drivers/keyboard.hinclude/cedos/drivers/keyboard.h

@@ -1,8 +1,8 @@

/*! \file - * Driver for PS/2 keyboard + * Driver for keyboards. */ -#ifndef OS_KEYBOARD_H -#define OS_KEYBOARD_H +#ifndef KEYBOARD_H +#define KEYBOARD_H #include <stdint.h>

@@ -30,5 +30,7 @@ } KB_DRIVER;

//! PS/2 keyboard driver (default driver) KB_DRIVER ps2_kb; + +KB_DRIVER *std_kb; #endif
A include/cedos/drivers/speaker.h

@@ -0,0 +1,37 @@

+/*! + * Driver for speakers. + */ +#ifndef SPEAKER_H +#define SPEAKER_H + +#include <stdint.h> + +/*! + * Interface for a speaker driver. + */ +typedef struct { + /*! + * Initializes the speaker. + * \return 1 on success, 0 on failure + */ + int (*init)(void); + + /*! + * Sets the current frequency of the speaker. + * \param freq Frequency to by output by the speaker. + * \param volume Volume of the sound. + * \return 1 on success, 0 on failure. + */ + int (*make_sound)(uint32_t freq, uint32_t volume); + + /*! + * Mutes the speaker. + * \return 1 on success, 0 on failure. + */ + int (*mute)(); +} SPEAKER_DRIVER; + +//! Driver for the bios speaker. +SPEAKER_DRIVER bios_sp; + +#endif
M include/cedos/interrupts.hinclude/cedos/interrupts.h

@@ -5,7 +5,10 @@ */

#ifndef OS_INTERRUPTS_H #define OS_INTERRUPTS_H - #include <stdint.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) /*! * Represents a single entry of the IDT.

@@ -19,8 +22,12 @@ uint16_t offset_16;

}__attribute__((packed)) IDT_ENTRY; typedef struct { - -} INTERRUPT_FRAME; + uint32_t eflags; + uint32_t cs; + uint32_t eip; +}__attribute__((packed)) INTERRUPT_FRAME; + +typedef uint32_t uword_t; int interrupts_init(void);
D include/cedos/kernel.h

@@ -1,13 +0,0 @@

-/*! - * Defines important kernel mode functions - */ -#ifndef KERNEL_H -#define KERNEL_H - -#include "cedos/drivers/console.h" - -__attribute__((always_inline)) inline void printk(const char* string) { - vga_con.write_s(string); -} - -#endif
M include/cedos/pic.hinclude/cedos/pic.h

@@ -4,15 +4,17 @@ */

#ifndef PIC_H #define PIC_H +#include "assembly.h" + #define PIC1_COMMAND 0x20 #define PIC1_DATA 0x21 #define PIC2_COMMAND 0xA0 #define PIC2_DATA 0xA1 -#define PIC_END_OF_INTERRUPT 0x20 - #define PIC1_OFFSET 0x20 #define PIC2_OFFSET 0x28 + +#define PIC_END_OF_INTERRUPT 0x20 /*! * Moves irqs to appropriate addresses and enables all PIC interrupts

@@ -33,5 +35,17 @@ * \param irq Number of the interrupt to mask.

* \return 1 on success, 0 on fail */ int pic_mask_interrupt(int irq); + +/*! + * Sends an end-of-interrupt-signal to the corresponding PIC. + */ +inline void pic1_eoi(void) { + outb(PIC_END_OF_INTERRUPT, PIC1_COMMAND); +} + +inline void pic2_eoi(void) { + outb(PIC_END_OF_INTERRUPT, PIC2_COMMAND); + outb(PIC_END_OF_INTERRUPT, PIC1_COMMAND); +} #endif
A include/cedos/pit.h

@@ -0,0 +1,39 @@

+/*! \file + * Provides an interface for the programmable interval timer (PIT). + */ +#ifndef PIT_H +#define PIT_H + +#include <stdint.h> + +/*! + * Specifies the accessed PIT channel. + */ +typedef enum { + PIT_CHANNEL_0 = (0), + PIT_CHANNEL_1 = (1), + PIT_CHANNEL_2 = (2) +} PIT_CHANNEL; + +/*! + * Specifies the operating mode of a channel. + */ +typedef enum { + PIT_MODE_0 = (0b000 << 1), + PIT_MODE_1 = (0b001 << 1), + PIT_MODE_2 = (0b010 << 1), + PIT_MODE_3 = (0b011 << 1), + PIT_MODE_4 = (0b100 << 1), + PIT_MODE_5 = (0b101 << 1), +} PIT_MODE; + +/*! + * Sets channel \p channel up to work in operating mode \p mode with frequency + * divider \p freq_div. + * \param channel Channel which is to be setup. + * \param mode Desired operating mode. + * \param freq_div Desired frequency divider. + */ +void pit_setup_channel(PIT_CHANNEL channel, PIT_MODE mode, uint16_t freq_div); + +#endif
A kernel/core.c

@@ -0,0 +1,121 @@

+#include "cedos/core.h" +#include "cedos/drivers/console.h" + +CON_DRIVER *core_con; + +void print_hex_char(uint8_t c) { + static char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + core_con->write_c(hex[c >> 4]); + core_con->write_c(hex[c & 0x0F]); +} + +void print_uint32(uint32_t value) { + uint8_t* mem = (uint8_t*)(&value); + for (int i = 0; i < 4; i++) { + print_hex_char(mem[3-i]); + } +} + +void memdump(void* start, uint32_t size) { + uint8_t* _start = (uint8_t*)((uint32_t)start & 0xFFFFFFF0); + uint8_t* _end = (uint8_t*)(((uint32_t)start + size + 0xF) & 0xFFFFFFF0); + + uint32_t first_line = (uint32_t)(_start); + uint32_t last_line = (uint32_t)(_end); + + for (uint32_t i = first_line; i < last_line; i += 0x10) { + core_con->write_c(' '); + print_uint32(i); + core_con->write_c(' '); + + for (int j = 0; j < 0x10; j++) { + uint8_t* p = (uint8_t*)(i | j); + + if (p >= start && p < (start + size)) { + print_hex_char(*p); + core_con->write_c(' '); + } else { + core_con->write_c(' '); + core_con->write_c(' '); + core_con->write_c(' '); + } + } + core_con->write_c('\n'); + } +} + +void stackdump(void) { + void* stack; + __asm__ volatile ("mov %%esp, %0" : "=a" (stack)); + printk("STACK DUMP:\n"); + memdump(stack, 0xC0400000 - (uint32_t)stack); +} + +void regdump(void) { + uint32_t eax, ebx, ecx, edx, + esi, edi, esp, ebp; + __asm__ volatile ( "mov %%eax, %0;" + "mov %%ebx, %1;" + "mov %%ecx, %2;" + "mov %%edx, %3;" + "mov %%esi, %4;" + "mov %%edi, %5;" + "mov %%esp, %6;" + "mov %%ebp, %7;" + : "=m" (eax), + "=m" (ebx), + "=m" (ecx), + "=m" (edx), + "=m" (esi), + "=m" (edi), + "=m" (esp), + "=m" (ebp)); + + printk(" EAX=%i EBX=%i ECX=%i EDX=%i\n", eax, ebx, ecx, edx); + printk(" ESI=%i EDI=%i ESP=%i EBP=%i\n", esi, edi, esp, ebp); +} + +void printk(const char* fmt, ...) { + va_list args; + va_start(args, fmt); + uint32_t index = 0; + + enum { + STATE_DEFAULT, + STATE_ARGUMENT, + } state = STATE_DEFAULT; + + while (*fmt) { + if (state == STATE_ARGUMENT && *fmt == 'i') { + print_uint32(va_arg(args, uint32_t)); + state = STATE_DEFAULT; + } else if (state == STATE_ARGUMENT && *fmt == 's') { + const char* string = va_arg(args, const char*); + while (*string) { core_con->write_c(*string++); } + state = STATE_DEFAULT; + } else if (state == STATE_ARGUMENT && *fmt == '%') { + core_con->write_c('%'); + state = STATE_DEFAULT; + } else if (*fmt == '%') { + state = STATE_ARGUMENT; + } else { + core_con->write_c(*fmt); + } + + fmt++; + } +} + +void kpanic(const char* string) { + printk(string); + core_con->write_c('\n'); + // register dump / stack dump + regdump(); + stackdump(); + while (1) {} +} + +int core_init(void) { + core_con = std_con; + return core_con->init(); +}
A kernel/drivers/bios_speaker.c

@@ -0,0 +1,59 @@

+#include "cedos/drivers/speaker.h" +#include "cedos/pit.h" +#include "assembly.h" + +#include <stdint.h> + +/*! + * Initializes the bios speaker. + * \return 1 on success, 0 on failure + */ +int bios_sp_init(void); + +/*! + * Sets the current frequency of the bios speaker. + * \param freq Frequency to by output by the bios speaker. + * \param volume Volume of the sound. + * \return 1 on success, 0 on failure. + */ +int bios_sp_make_sound(uint32_t freq, uint32_t volume); + +/*! + * Mutes the bios speaker. + * \return 1 on success, 0 on failure. + */ +int bios_sp_mute(); + +//! Driver for the bios speaker. +SPEAKER_DRIVER bios_sp = { + bios_sp_init, + bios_sp_make_sound, + bios_sp_mute +}; + +int bios_sp_init(void) { + bios_sp_mute(); + return 1; +} + +int bios_sp_make_sound(uint32_t freq, uint32_t volume) { + /** + * volume for the bios speaker: + * - 0: mute + * - other: full volume + */ + + if (volume) { + pit_setup_channel(PIT_CHANNEL_2, PIT_MODE_3, (uint16_t)(1193180 / freq)); + outb(inb(0x61) | 0b00000011, 0x61); + } else { + bios_sp_mute(); + } + + return 1; +} + +int bios_sp_mute() { + outb(inb(0x61) & (~0b00000011), 0x61); + return 1; +}
A kernel/drivers/console.c

@@ -0,0 +1,3 @@

+#include "cedos/drivers/console.h" + +CON_DRIVER *std_con = &vga_con;
A kernel/drivers/keyboard.c

@@ -0,0 +1,3 @@

+#include "cedos/drivers/keyboard.h" + +KB_DRIVER *std_kb = &ps2_kb;
M kernel/interrupts.ckernel/interrupts.c

@@ -1,7 +1,9 @@

#include "cedos/interrupts.h" #include "cedos/drivers/console.h" +#include "cedos/pic.h" -#define HARDWARE_INTERRUPT (0b10001110) +#define INT_GATE (0b10001110) +#define TRAP_GATE (0b10001111) #define SYSCALL_INTERRUPT (0b11101110) #define array_sizeof(array) (sizeof(array)/sizeof(array[0]))

@@ -14,18 +16,38 @@ (uint8_t)(type), \

(uint16_t)(0xC000) \ } -__attribute__((interrupt)) void default_isr(INTERRUPT_FRAME *frame) { - vga_con.write_s("interrupt was issued\n"); +INTERRUPT(default_isr, frame) { + printk("interrupt was issued\n"); +} + +INTERRUPT(breakpoint_isr, frame) { + printk("BREAKPOINT WAS HIT\n"); } -__attribute__((interrupt)) void breakpoint_isr(INTERRUPT_FRAME *frame) { - vga_con.write_s("BREAKPOINT WAS HIT\n"); +EXCEPTION(page_fault_isr, frame, error_code) { + volatile uint32_t faulty_addr; + __asm__ volatile ("mov %%cr2, %0" : "=a" (faulty_addr)); + printk("PAGE FAULT: %i", faulty_addr); + while (1) {} // dump registers to stdout } -__attribute__((interrupt)) void double_fault_isr(INTERRUPT_FRAME *frame) { - vga_con.write_s("CRITICAL: DOUBLE FAULT\n"); - //while (1) {} +EXCEPTION(double_fault_isr, frame, error_code) { + kpanic("CRITICAL: DOUBLE FAULT"); +} + +EXCEPTION(gpf_isr, frame, error_code) { + kpanic("CRITICAL: GENERAL PROTECTION FAULT"); +} + +INTERRUPT(pic1_handler, frame) { + printk("PIC1 INTERRUPT\n"); + pic1_eoi(); +} + +INTERRUPT(pic2_handler, frame) { + printk("PIC2 INTERRUPT\n"); + pic2_eoi(); } IDT_ENTRY IDT[31];

@@ -36,7 +58,6 @@ 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 {

@@ -49,22 +70,25 @@ };

int interrupts_init(void) { for (uint32_t i = 0; i < array_sizeof(IDT); i++) { - switch (i) { - case 0x03: - install_interrupt(i, breakpoint_isr, 0x08, HARDWARE_INTERRUPT); - break; - case 0x08: - install_interrupt(i, double_fault_isr, 0x08, HARDWARE_INTERRUPT); - break; - default: - install_interrupt(i, default_isr, 0x08, HARDWARE_INTERRUPT); - break; + if (i == 0x03) { + install_interrupt(i, breakpoint_isr, 0x08, INT_GATE); + } else if (i == 0x08) { + install_interrupt(i, double_fault_isr, 0x08, INT_GATE); + } else if (i == 0x0e) { + install_interrupt(i, page_fault_isr, 0x08, INT_GATE); + } else if (i == 0x0d) { + install_interrupt(i, gpf_isr, 0x08, INT_GATE); + } else if (i >= 0x20 || i < 0x28) { + install_interrupt(i, pic1_handler, 0x08, INT_GATE); + } else if (i >= 0x28 || i < 0x30) { + install_interrupt(i, pic2_handler, 0x08, INT_GATE); + } else { + install_interrupt(i, default_isr, 0x08, INT_GATE); } } __asm__ volatile ( - "lidt (%0)\n" - "sti" : : + "lidt (%0)\n" : : "m" (IDT_DESC) );
M kernel/main.ckernel/main.c

@@ -3,11 +3,12 @@ #include "cedos/interrupts.h"

#include "cedos/pic.h" #include "cedos/scheduler.h" #include "cedos/mm/paging.h" -#include "cedos/kernel.h" +#include "cedos/core.h" +#include "assert.h" int os_init(void) { - vga_con.init(); - printk("TTY output initialized.\n"); + core_init(); + printk("Core functions initialized.\n"); printk("Initializing PIC..."); pic_init();

@@ -17,17 +18,32 @@ printk("Initializing interrupts...");

interrupts_init(); printk("done.\n"); + printk("Activating interrupts..."); + sti(); + printk("done.\n"); + + printk("Initializing scheduler..."); + sched_init(); + printk("done.\n"); + printk("Initialization finished.\n--------------\n"); return 1; } +void infodump(void) { + uint32_t res[4]; + cpuid(0, &res[0], &res[2], &res[1]); + res[3] = 0; + printk("CPU manufacturer: %s\n", res); +} + int os_main(void) { - //const char* string[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; + infodump(); - printk("Starting scheduler.\n"); - sched_exec(create_empty_page_dir(), (void*)0, (void*)0); + kpanic("SIMULATED KERNEL PANIC"); + // won't be executed printk("Main procedure terminating.\n"); return 0; }
A kernel/pit.c

@@ -0,0 +1,17 @@

+#include "cedos/pit.h" +#include "assembly.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) { + cli(); + outb(((uint8_t)channel << 6) | PIT_ACCESS_MODE_LO_HI | (uint8_t)mode, PIT_COMMAND_PORT); + nop(); nop(); nop(); nop(); + + 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(); +}
M kernel/scheduler.ckernel/scheduler.c

@@ -2,7 +2,7 @@ #include "cedos/scheduler.h"

#include "cedos/process.h" #include "cedos/mm/paging.h" #include "cedos/drivers/console.h" -#include "cedos/kernel.h" +#include "cedos/core.h" PROCESS* get_slot(void) { static PROCESS free_slots[4];

@@ -29,5 +29,15 @@ }

int sched_init(void) { // TODO: create and start idle process + + //sched_exec(create_empty_page_dir(), (void*)0, (void*)0); return 1; +} + +int sched_dispatcher(void) { + +} + +INTERRUPT(sched_interrupt, frame) { + }
M makefilemakefile

@@ -6,26 +6,28 @@ export DEBUG_DIR = $(CURRENT_DIR)/debug

export GCC_PREFIX = $(HOME)/opt/cross/bin/i686-elf- +GLOBAL_BUILD = $(CURRENT_DIR)/build ifdef DEBUG -GLOBAL_BUILD = $(CURRENT_DIR)/build/debug -GCC_OPTIONS = -D DEBUG -g -O0 -Wno-write-strings -Qn -Wall -Wextra -fno-exceptions -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only +GCC_OPTIONS = -D DEBUG -g -O0 -Wno-write-strings -Qn -Wall -Wextra -fno-exceptions -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only -mno-red-zone +LOCAL_BUILD = $(GLOBAL_BUILD)/debug else -GLOBAL_BUILD = $(CURRENT_DIR)/build/release -GCC_OPTIONS = -O1 -Wno-write-strings -Qn -Wall -Wextra -fno-exceptions -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only +GCC_OPTIONS = -O1 -Wno-write-strings -Qn -Wall -Wextra -fno-exceptions -nostdlib -nostartfiles -ffreestanding -mgeneral-regs-only -mno-red-zone +LOCAL_BUILD = $(GLOBAL_BUILD)/release endif export GCC_OPTIONS -LOCAL_BUILD = $(GLOBAL_BUILD) .PHONY: build build: -> @mkdir $(GLOBAL_BUILD) 2> /dev/null; true +> @mkdir $(LOCAL_BUILD) 2> /dev/null; true > $(MAKE) GLOBAL_BUILD=$(LOCAL_BUILD) -C boot build > $(MAKE) GLOBAL_BUILD=$(LOCAL_BUILD) -C kernel build -> $(GCC_PREFIX)ld $(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 +> $(GCC_PREFIX)ld $(LOCAL_BUILD)/*.o -T link.txt -Map=$(DEBUG_DIR)/mapfile.txt -o $(GLOBAL_BUILD)/base.o +> $(GCC_PREFIX)objcopy --only-keep-debug $(GLOBAL_BUILD)/base.o $(DEBUG_DIR)/base.sym +> $(GCC_PREFIX)objcopy -O binary $(GLOBAL_BUILD)/base.o $(GLOBAL_BUILD)/base.img +> $(GCC_PREFIX)objdump -D $(GLOBAL_BUILD)/base.o > $(DEBUG_DIR)/objdump.txt + .PHONY: clear clear:
M run.shrun.sh

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

-qemu -drive index=0,if=floppy,format=raw,file=build/base.img -m 64 -monitor stdio -no-reboot -d int,cpu_reset 2> debug/err.log+qemu -drive index=0,if=floppy,format=raw,file=build/base.img -m 64 -monitor stdio -no-reboot -d int,cpu_reset,exec,in_asm 2> debug/err.log