CeDOS - Commit 4a774894

PIC driver implemented
Celina Sophie Kalus
Wed, 27 Dec 2017 22:38:34 +0100
17 files changed, 353 insertions(+), 55 deletions(-)
M include/assembly.hinclude/assembly.h

@@ -12,7 +12,7 @@ * \param msg The byte to be sent.

* \param port The destination port. */ __attribute((always_inline)) inline void outb(uint8_t msg, uint16_t port) { - __asm__ volatile ("outb %0, %1" : "=a" (msg), "=Nd" (port)); + __asm__ volatile ("outb %0, %1" : : "a" (msg), "Nd" (port)); } /*!

@@ -25,5 +25,17 @@ uint8_t msg;

__asm__ volatile ("inb %1, %0" : "=a" (msg) : "Nd" (port)); return msg; } + +/*! + * nop + */ +__attribute__((always_inline)) inline void nop(void) { + __asm__ volatile ("nop"); +} + +/*! + * Causes an interrupt + */ +#define int(n) __asm__ volatile ("int $" #n) #endif
A include/common.h

@@ -0,0 +1,4 @@

+#ifndef COMMON_H +#define COMMON_H + +#endif
M kernel/os_entry.skernel/os_entry.s

@@ -6,8 +6,15 @@ mov $__KERNEL_STACK_ADDR, %eax

mov %eax, %esp mov %esp, %ebp + # initialize kernel + call os_init + jz error + # call main - call main + call os_main loop: jmp loop + +error: + jmp error
M kernel/os_interrupts.ckernel/os_interrupts.c

@@ -13,23 +13,19 @@ 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)) volatile void default_isr(INTERRUPT_FRAME *frame) { + text_write("interrupt was issued\n"); } -__attribute__((interrupt)) void breakpoint_isr(struct interrupt_frame *frame) { - write("BREAKPOINT WAS HIT\n"); +__attribute__((interrupt)) volatile void breakpoint_isr(INTERRUPT_FRAME *frame) { + text_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) {} +__attribute__((interrupt)) volatile void double_fault_isr(INTERRUPT_FRAME *frame) { + text_write("CRITICAL: DOUBLE FAULT\n"); + //while (1) {} } IDT_ENTRY IDT[31];

@@ -51,16 +47,18 @@ sizeof(IDT),

IDT }; -void init_interrupts(void) { +void 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; } }
M kernel/os_interrupts.hkernel/os_interrupts.h

@@ -18,6 +18,10 @@ uint8_t type_attr;

uint16_t offset_16; }__attribute__((packed)) IDT_ENTRY; -void init_interrupts(void); +typedef struct { + +} INTERRUPT_FRAME; + +void interrupts_init(void); #endif
A kernel/os_keyboard.c

@@ -0,0 +1,28 @@

+#include "os_keyboard.h" +#include "os_interrupts.h" +#include "os_pic.h" +#include "assembly.h" + + + +/*! + * Initializes the keyboard. + * \return 1 on success, 0 on fail + */ +int keyboard_init(void) { + +} + +/*! + * Reads a single character from the keyboard + * \return A single char corresponding to a key press. + */ +uint8_t keyboard_read_c(void) { + static uint32_t keycode = 0; + + keycode <<= 8; +} + +__attribute__((interrupt)) volatile void keyboard_int_handler(INTERRUPT_FRAME *frame) { + +}
A kernel/os_keyboard.h

@@ -0,0 +1,21 @@

+/*! \file + * Driver for PS/2 keyboard + */ +#ifndef OS_KEYBOARD_H +#define OS_KEYBOARD_H + +#include <stdint.h> + +/*! + * Initializes the keyboard. + * \return 1 on success, 0 on fail + */ +int keyboard_init(void); + +/*! + * Reads a single character from the keyboard + * \return A single char corresponding to a key press. + */ +uint8_t keyboard_read_c(void); + +#endif
M kernel/os_main.ckernel/os_main.c

@@ -1,26 +1,19 @@

#include "os_text.h" #include "os_interrupts.h" +#include "os_pic.h" -int main(void) { - init_interrupts(); +int os_init(void) { + pic_init(); + + interrupts_init(); + text_init(); +} + +int os_main(void) { const char* string[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; - clear(); - for (int i = 0; i < 50; i++) { - write("LINE "); - write(string[i / 10]); - write(string[i % 10]); - write("\n"); - } - write( "SOMEBODY ONCE TOLD ME " - "THE WORLD IS GONNA ROLL ME " - "I AINT THE SHARPEST TOOL IN THE SHED " - "SHE WAS LOOKING KINDA DUMB " - "WITH HER FINGER AND HER THUMB " - "IN THE SHAPE OF AN L ON HER FOREHEAD" - ); - //backspace(); + text_write("Hallo! :)"); return 0; }
A kernel/os_memory.c

@@ -0,0 +1,35 @@

+#include "os_memory.h" + +/*! + * Allocates a block of \p size bytes of memory. (KERNEL MODE) + * \param size Size in bytes of the requested block of memory. + * \return Memory address to the new memory block + */ +void* os_kernel_malloc(size_t size) { + +} + +/*! + * Frees a previously allocated block of memory. (KERNEL MODE) + * \param ptr Pointer to the memory block to be freed. + */ +void os_kernel_free(void* ptr) { + +} + +/*! + * Allocates a block of \p size bytes of memory. (USER MODE) + * \param size Size in bytes of the requested block of memory. + * \return Memory address to the new memory block + */ +void* os_user_malloc(size_t size) { + +} + +/*! + * Frees a previously allocated block of memory. (USER MODE) + * \param ptr Pointer to the memory block to be freed. + */ +void os_user_free(void* ptr) { + +}
A kernel/os_memory.h

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

+/*! \file + * Provides functions for memory allocation. + */ +#ifndef OS_MEMORY_H +#define OS_MEMORY_H + +#include <stdint.h> + +typedef uint32_t size_t; + +/*! + * Allocates a block of \p size bytes of memory. (KERNEL MODE) + * \param size Size in bytes of the requested block of memory. + * \return Memory address to the new memory block + */ +void* os_kernel_malloc(size_t size); + +/*! + * Frees a previously allocated block of memory. (KERNEL MODE) + * \param ptr Pointer to the memory block to be freed. + */ +void os_kernel_free(void* ptr); + +/*! + * Allocates a block of \p size bytes of memory. (USER MODE) + * \param size Size in bytes of the requested block of memory. + * \return Memory address to the new memory block + */ +void* os_user_malloc(size_t size); + +/*! + * Frees a previously allocated block of memory. (USER MODE) + * \param ptr Pointer to the memory block to be freed. + */ +void os_user_free(void* ptr); + +#endif
M kernel/os_paging.ckernel/os_paging.c

@@ -2,11 +2,53 @@ #include "os_paging.h"

#include "linker.h" #include "os_page_allocator.h" +//#define MAKE_PAGE_ENTRY(addr, flags) (uint32_t)(((uint32_t)(addr) & 0xFFFFF000) | (flags)) + +#define PAGE_DIRECTORY (PAGE_DIR_ENTRY[PAGE_ENTRY_COUNT]) +#define PAGE_TABLE (PAGE_TABLE_ENTRY[PAGE_ENTRY_COUNT]) + +#define PAGE_DIR_INDEX(addr) (((uint32_t)(addr) >> 22) % PAGE_ENTRY_COUNT) +#define PAGE_TABLE_INDEX(addr) (((uint32_t)(addr) >> 12) % PAGE_ENTRY_COUNT) + +#define PAGE_TABLE_MAPPED_ADDR(index) ((PAGE_TABLE_ENTRY*)(PAGE_SIZE * PAGE_ENTRY_COUNT * (PAGE_ENTRY_COUNT - 1) + PAGE_SIZE * index)) +#define PAGE_DIR_MAPPED_ADDR ((PAGE_DIR_ENTRY*)(PAGE_TABLE_MAPPED_ADDR(PAGE_ENTRY_COUNT - 1))) + +/* +int map_page_to(void* page_addr, uint32_t dir_index, uint32_t table_index) { + PAGE_DIR_ENTRY* page_dir = PAGE_DIR_MAPPED_ADDR; + + if (!(page_dir[dir_index].present)) { + #warning implement this + // acquire new page table + } + + PAGE_TABLE_ENTRY* page_table = PAGE_TABLE_MAPPED_ADDR(dir_index); + + if (!(page_table[table_index].present)) { + #warning implement this + // map page + } else { + // didn't works + return -1; + } +} + void* map_first_free(void* page_dir, void* search_start, void* page) { + uint32_t table_start_i = PAGE_TABLE_INDEX(search_start); + + for (uint32_t dir_i = PAGE_DIR_INDEX(search_start); dir_i < (PAGE_ENTRY_COUNT - 1); dir_i++) { + for (uint32_t table_i = table_start_i; table_i < (PAGE_ENTRY_COUNT - 1); table_i++) { + if (map_page_to(page, )) + } + + table_start_i = 0; + } + return 0; } void* create_empty_page_dir(void) { return 0; #warning IMPLEMENT STH. -}+} +*/
M kernel/os_paging.hkernel/os_paging.h

@@ -8,10 +8,10 @@

#include <stdint.h> //! Number of entries within a page table/directory. -#define PAGE_ENTRY_COUNT (1 << 10) +#define PAGE_ENTRY_COUNT (uint32_t)(1 << 10) //! Size of a single page or page table/directory. -#define PAGE_SIZE (1 << 12) +#define PAGE_SIZE (uint32_t)(1 << 12) //! Represents a single page entry in a page table. typedef union {

@@ -70,13 +70,5 @@ * Uses a free page to generate a new page directory which maps its last entry to itself.

* \return Address of new page directory. */ void* create_empty_page_dir(void); - -#define MAKE_PAGE_ENTRY(addr, flags) (uint32_t)(((uint32_t)(addr) & 0xFFFFF000) | (flags)) - -#define PAGE_DIRECTORY (PAGE_DIR_ENTRY[PAGE_ENTRY_COUNT]) -#define PAGE_TABLE (PAGE_TABLE_ENTRY[PAGE_ENTRY_COUNT]) - -#define PAGE_DIR_INDEX(addr) ((uint32_t)(addr) >> 22) -#define PAGE_TABLE_INDEX(addr) ((uint32_t)(addr) >> 12) #endif
A kernel/os_pic.c

@@ -0,0 +1,73 @@

+#include "os_pic.h" +#include "assembly.h" +#include "common.h" + +/*! + * Moves irqs to appropriate addresses and enables all PIC interrupts + * \return 1 on success, 0 on fail + */ +volatile int pic_init(void) { + // start initialization sequence + outb(0x11, PIC1_COMMAND); + outb(0x11, PIC2_COMMAND); + nop(); nop(); nop(); nop(); + + // set offsets + outb(PIC1_OFFSET, PIC1_DATA); + outb(PIC2_OFFSET, PIC2_DATA); + nop(); nop(); nop(); nop(); + + // set wiring info + outb(0b00000100, PIC1_DATA); + outb(0b00000010, PIC2_DATA); + nop(); nop(); nop(); nop(); + + // set operating mode (8086) + outb(0x01, PIC1_DATA); + outb(0x01, PIC2_DATA); + nop(); nop(); nop(); nop(); + + // clear interrupt masks + outb(0xff, PIC1_DATA); + outb(0xff, PIC2_DATA); +} + +/*! + * Unmasks interrupt number \p irq. + * \param irq Number of the interrupt to unmask. + * \return 1 on success, 0 on fail + */ +int pic_unmask_interrupt(int irq) { + uint16_t port; + + if (irq >= 8) { + port = PIC1_DATA; + } else { + port = PIC2_DATA; + irq -= 8; + } + + uint8_t mask = inb(port); + mask &= ~(1 << irq); + outb(mask, port); +} + +/*! + * Masks interrupt number \p irq. + * \param irq Number of the interrupt to mask. + * \return 1 on success, 0 on fail + */ +int pic_mask_interrupt(int irq) { + uint16_t port; + + if (irq >= 8) { + port = PIC1_DATA; + } else { + port = PIC2_DATA; + irq -= 8; + } + + uint8_t mask = inb(port); + mask |= 1 << irq; + outb(mask, port); +}
A kernel/os_pic.h

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

+/*! \file + * Interface for accessing the programmable interrupt contoller (PIC). + */ +#ifndef OS_PIC_H +#define OS_PIC_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 + +/*! + * Moves irqs to appropriate addresses and enables all PIC interrupts + * \return 1 on success, 0 on fail + */ +int pic_init(void); + +/*! + * Unmasks interrupt number \p irq. + * \param irq Number of the interrupt to unmask. + * \return 1 on success, 0 on fail + */ +int pic_unmask_interrupt(int irq); + +/*! + * Masks interrupt number \p irq. + * \param irq Number of the interrupt to mask. + * \return 1 on success, 0 on fail + */ +int pic_mask_interrupt(int irq); + +#endif
M kernel/os_text.ckernel/os_text.c

@@ -70,7 +70,7 @@ outb(0x0E, VGA_INDEX_REG);

outb((uint8_t)(pos >> 8), VGA_DATA_REG); } -void backspace(void) { +void text_backspace(void) { if (column == 0 && line > 0) { line--; column = VGA_TEXTMODE_COLUMNS - 1;

@@ -82,21 +82,21 @@ set_char(0);

set_cursor(line, column); } -void write_n(const char *string, uint32_t num) { +void text_write_n(const char *string, uint32_t num) { for (uint32_t i = 0; i < num; i++) { write_char(string[0]); } set_cursor(line, column); } -void write(const char *string) { +void text_write(const char *string) { while (*string) { write_char(*(string++)); } set_cursor(line, column); } -void write_c(const char c) { +void text_write_c(const char c) { write_char(c); set_cursor(line, column); }

@@ -108,7 +108,7 @@ outb(0x0B, VGA_INDEX_REG);

outb((inb(VGA_DATA_REG) & 0xE0) | 0x0F, VGA_DATA_REG); } -void clear(void) { +void text_clear(void) { for (int i = 0; i < VGA_TEXTMODE_CELLS; i++) { VGA_TEXTMODE_MEM[2 * i] = 0; VGA_TEXTMODE_MEM[2 * i + 1] = 0;

@@ -116,6 +116,13 @@ }

line = 0; column = 0; +} + +int text_init(void) { + text_clear(); + enable_cursor(); set_cursor(line, column); -} + + return 1; +}
M kernel/os_text.hkernel/os_text.h

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

/*! \file - * Low-level driver for VGA textmode output + * Driver for VGA textmode output */ #ifndef TEXT_H #define TEXT_H

@@ -11,28 +11,34 @@ * Prints a number of characters of a string to the display.

* \param string String from which to print characters. * \param num Number of characters to print */ -void write_n(const char *string, uint32_t num); +void text_write_n(const char *string, uint32_t num); /*! * Prints a single character to the display. * \param c Character to print. */ -void write_c(const char c); +void text_write_c(const char c); /*! * Prints a null-terminated string to the display. * \param string Null-terminated string to print. */ -void write(const char *string); +void text_write(const char *string); + +/*! + * Initializes VGA textmode + * \return 1 on success, 0 on fail + */ +int text_init(void); /*! * Clears the entire display and resets the cursor. */ -void clear(); +void text_clear(void); /*! * Deletes a single character of the display and moves the cursor back. */ -void backspace(void); +void text_backspace(void); #endif
M makefilemakefile

@@ -17,6 +17,8 @@

export GLOBAL_BUILD export GCC_OPTIONS +export LOCAL_BUILD = $(GLOBAL_BUILD) + .PHONY: build build: > @mkdir $(GLOBAL_BUILD) 2> /dev/null; true