summaryrefslogtreecommitdiff
path: root/src/c
diff options
context:
space:
mode:
authorAleksa Vučković <aleksav013@gmail.com>2021-10-25 00:36:33 +0200
committerAleksa Vučković <aleksav013@gmail.com>2021-10-25 00:36:33 +0200
commit20dd72e40dc2728d3c5335d860e4b8ab8da14fcc (patch)
treedabdfdf736c45f9632fa1388d2144b1de7a438b0 /src/c
parent0bca634f7e70b05239f46f3bd40bb37468d67957 (diff)
Changing build system to recursive make
Diffstat (limited to 'src/c')
-rw-r--r--src/c/Makefile5
-rw-r--r--src/c/gdt.c48
-rw-r--r--src/c/heap.c167
-rw-r--r--src/c/idt.c101
-rw-r--r--src/c/kernel.c17
-rw-r--r--src/c/keyboard.c110
-rw-r--r--src/c/keymap.c173
-rw-r--r--src/c/stdio.c37
-rw-r--r--src/c/string.c113
-rw-r--r--src/c/tty.c75
-rw-r--r--src/c/vga.c126
11 files changed, 972 insertions, 0 deletions
diff --git a/src/c/Makefile b/src/c/Makefile
new file mode 100644
index 0000000..7c5d1af
--- /dev/null
+++ b/src/c/Makefile
@@ -0,0 +1,5 @@
+.PHONY: all
+all: $(C_OBJECTS)
+
+$(BUILD_DIR)/%.o: %.c
+ $(CC) -c $< -o $@ -std=gnu99 $(CFLAGS)
diff --git a/src/c/gdt.c b/src/c/gdt.c
new file mode 100644
index 0000000..8fcda3a
--- /dev/null
+++ b/src/c/gdt.c
@@ -0,0 +1,48 @@
+#include"../include/types.h"
+
+struct gdt_entry
+{
+ uint16_t limit;
+ uint16_t base1;
+ uint8_t base2;
+ uint8_t access;
+ uint8_t limit_flags;
+ uint8_t base3;
+} __attribute__((packed));
+
+struct gdt_pointer
+{
+ uint16_t size;
+ uint32_t offset;
+} __attribute__((packed));
+
+// asm function
+extern void load_gdt(struct gdt_pointer *gdtp);
+
+struct gdt_entry gdt[3];
+struct gdt_pointer gdtp;
+
+void init_gdt_entry(size_t num, uint32_t limit, uint32_t base, uint8_t access, uint8_t limit_flags)
+{
+ gdt[num].limit=limit;
+ gdt[num].base1=(base & 0xffff);
+ gdt[num].base2=(base & 0xff0000) >> 16;
+ gdt[num].access=access;
+ gdt[num].limit_flags=limit_flags;
+ gdt[num].base3=(base & 0xff000000) >> 24;
+}
+
+void init_gdt_table()
+{
+ gdtp.size=sizeof(gdt)-1;
+ gdtp.offset=(uint32_t)&gdt;
+
+ //null
+ init_gdt_entry(0,0,0,0,0);
+ //code
+ init_gdt_entry(1,0xffffffff,0,0b10011010,0b11001111);
+ //data
+ init_gdt_entry(2,0xffffffff,0,0b10010010,0b11001111);
+
+ load_gdt(&gdtp);
+}
diff --git a/src/c/heap.c b/src/c/heap.c
new file mode 100644
index 0000000..1bad05e
--- /dev/null
+++ b/src/c/heap.c
@@ -0,0 +1,167 @@
+#include"../include/types.h"
+
+/*
+ 2014 Leonard Kevin McGuire Jr (www.kmcg3413.net) (kmcg3413@gmail.com)
+ 2016 Clément Gallet (provided bug fixes)
+*/
+typedef struct _KHEAPBLOCKBM {
+ struct _KHEAPBLOCKBM *next;
+ uint32_t size;
+ uint32_t used;
+ uint32_t bsize;
+ uint32_t lfb;
+} KHEAPBLOCKBM;
+
+typedef struct _KHEAPBM {
+ KHEAPBLOCKBM *fblock;
+} KHEAPBM;
+
+void k_heapBMInit(KHEAPBM *heap) {
+ heap->fblock = 0;
+}
+
+int k_heapBMAddBlock(KHEAPBM *heap, uintptr_t addr, uint32_t size, uint32_t bsize) {
+ KHEAPBLOCKBM *b;
+ uint32_t bcnt;
+ uint32_t x;
+ uint8_t *bm;
+
+ b = (KHEAPBLOCKBM*)addr;
+ b->size = size - sizeof(KHEAPBLOCKBM);
+ b->bsize = bsize;
+
+ b->next = heap->fblock;
+ heap->fblock = b;
+
+ bcnt = b->size / b->bsize;
+ bm = (uint8_t*)&b[1];
+
+ /* clear bitmap */
+ for (x = 0; x < bcnt; ++x) {
+ bm[x] = 0;
+ }
+
+ /* reserve room for bitmap */
+ bcnt = (bcnt / bsize) * bsize < bcnt ? bcnt / bsize + 1 : bcnt / bsize;
+ for (x = 0; x < bcnt; ++x) {
+ bm[x] = 5;
+ }
+
+ b->lfb = bcnt - 1;
+
+ b->used = bcnt;
+
+ return 1;
+}
+
+static uint8_t k_heapBMGetNID(uint8_t a, uint8_t b) {
+ uint8_t c;
+ for (c = a + 1; c == b || c == 0; ++c);
+ return c;
+}
+
+void *k_heapBMAlloc(KHEAPBM *heap, uint32_t size) {
+ KHEAPBLOCKBM *b;
+ uint8_t *bm;
+ uint32_t bcnt;
+ uint32_t x, y, z;
+ uint32_t bneed;
+ uint8_t nid;
+
+ /* iterate blocks */
+ for (b = heap->fblock; b; b = b->next) {
+ /* check if block has enough room */
+ if (b->size - (b->used * b->bsize) >= size) {
+
+ bcnt = b->size / b->bsize;
+ bneed = (size / b->bsize) * b->bsize < size ? size / b->bsize + 1 : size / b->bsize;
+ bm = (uint8_t*)&b[1];
+
+ for (x = (b->lfb + 1 >= bcnt ? 0 : b->lfb + 1); x < b->lfb; ++x) {
+ /* just wrap around */
+ if (x >= bcnt) {
+ x = 0;
+ }
+
+ if (bm[x] == 0) {
+ /* count free blocks */
+ for (y = 0; bm[x + y] == 0 && y < bneed && (x + y) < bcnt; ++y);
+
+ /* we have enough, now allocate them */
+ if (y == bneed) {
+ /* find ID that does not match left or right */
+ nid = k_heapBMGetNID(bm[x - 1], bm[x + y]);
+
+ /* allocate by setting id */
+ for (z = 0; z < y; ++z) {
+ bm[x + z] = nid;
+ }
+
+ /* optimization */
+ b->lfb = (x + bneed) - 2;
+
+ /* count used blocks NOT bytes */
+ b->used += y;
+
+ return (void*)(x * b->bsize + (uintptr_t)&b[1]);
+ }
+
+ /* x will be incremented by one ONCE more in our FOR loop */
+ x += (y - 1);
+ continue;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+void k_heapBMFree(KHEAPBM *heap, void *ptr) {
+ KHEAPBLOCKBM *b;
+ uintptr_t ptroff;
+ uint32_t bi, x;
+ uint8_t *bm;
+ uint8_t id;
+ uint32_t max;
+
+ for (b = heap->fblock; b; b = b->next) {
+ if ((uintptr_t)ptr > (uintptr_t)b && (uintptr_t)ptr < (uintptr_t)b + sizeof(KHEAPBLOCKBM) + b->size) {
+ /* found block */
+ ptroff = (uintptr_t)ptr - (uintptr_t)&b[1]; /* get offset to get block */
+ /* block offset in BM */
+ bi = ptroff / b->bsize;
+ /* .. */
+ bm = (uint8_t*)&b[1];
+ /* clear allocation */
+ id = bm[bi];
+ /* oddly.. GCC did not optimize this */
+ max = b->size / b->bsize;
+ for (x = bi; bm[x] == id && x < max; ++x) {
+ bm[x] = 0;
+ }
+ /* update free block count */
+ b->used -= x - bi;
+ return;
+ }
+ }
+
+ /* this error needs to be raised or reported somehow */
+ return;
+}
+
+KHEAPBM kheap;
+
+void heap()
+{
+ KHEAPBM kheap;
+ char *ptr;
+
+ k_heapBMInit(&kheap); /* initialize the heap */
+ k_heapBMAddBlock(&kheap, 0x100000, 0x100000, 16); /* add block to heap
+ (starting 1MB mark and length of 1MB)
+ with default block size of 16 bytes
+ */
+ ptr = (char*)k_heapBMAlloc(&kheap, 256); /* allocate 256 bytes (malloc) */
+ k_heapBMFree(&kheap, ptr); /* free the pointer (free) */
+}
diff --git a/src/c/idt.c b/src/c/idt.c
new file mode 100644
index 0000000..274db6d
--- /dev/null
+++ b/src/c/idt.c
@@ -0,0 +1,101 @@
+#include"../include/types.h"
+
+#define INTERRUPT_GATE_32 0x8e
+
+#define KERNEL_CODE 0x08
+#define KERNEL_DATA 0x10
+
+#define PIC1_COMMAND_PORT 0x20
+#define PIC1_DATA_PORT 0x21
+#define PIC2_COMMAND_PORT 0xA0
+#define PIC2_DATA_PORT 0xA1
+
+struct idt_entry
+{
+ uint16_t offset1;
+ uint16_t selector;
+ uint8_t zero;
+ uint8_t type_attr;
+ uint16_t offset2;
+} __attribute__((packed));
+
+struct idt_pointer
+{
+ uint16_t size;
+ uint32_t offset;
+} __attribute__((packed));
+
+// asm function
+extern void load_idt(struct idt_pointer *idtp);
+extern void keyboard_handler();
+extern void ioport_out(uint8_t port, char data);
+
+struct idt_entry idt[256];
+struct idt_pointer idtp;
+
+void init_idt_entry(size_t num, uint32_t offset, uint16_t selector, uint8_t type_attr)
+{
+ idt[num].offset1=(offset & 0xffff);
+ idt[num].selector=selector;
+ idt[num].zero=0;
+ idt[num].type_attr=type_attr;
+ idt[num].offset2=(offset & 0xffff0000)>>16;
+}
+
+void init_idt_table()
+{
+ // Program the PICs - Programmable Interrupt Controllers
+ // Background:
+ // In modern architectures, the PIC is not a separate chip.
+ // It is emulated in the CPU for backwards compatability.
+ // The APIC (Advanced Programmable Interrupt Controller)
+ // is the new version of the PIC that is integrated into the CPU.
+ // Default vector offset for PIC is 8
+ // This maps IRQ0 to interrupt 8, IRQ1 to interrupt 9, etc.
+ // This is a problem. The CPU reserves the first 32 interrupts for
+ // CPU exceptions such as divide by 0, etc.
+ // In programming the PICs, we move this offset to 0x2 (32) so that
+ // we can handle all interrupts coming to the PICs without overlapping
+ // with any CPU exceptions.
+
+ // Send ICWs - Initialization Command Words
+ // PIC1: IO Port 0x20 (command), 0xA0 (data)
+ // PIC2: IO Port 0x21 (command), 0xA1 (data)
+ // ICW1: Initialization command
+ // Send a fixed value of 0x11 to each PIC to tell it to expect ICW2-4
+ // Restart PIC1
+ ioport_out(PIC1_COMMAND_PORT, 0x11);
+ ioport_out(PIC2_COMMAND_PORT, 0x11);
+ // ICW2: Vector Offset (this is what we are fixing)
+ // Start PIC1 at 32 (0x20 in hex) (IRQ0=0x20, ..., IRQ7=0x27)
+ // Start PIC2 right after, at 40 (0x28 in hex)
+ ioport_out(PIC1_DATA_PORT, 0x20);
+ ioport_out(PIC2_DATA_PORT, 0x28);
+ // ICW3: Cascading (how master/slave PICs are wired/daisy chained)
+ // Tell PIC1 there is a slave PIC at IRQ2 (why 4? don't ask me - https://wiki.osdev.org/8259_PIC)
+ // Tell PIC2 "its cascade identity" - again, I'm shaky on this concept. More resources in notes
+ ioport_out(PIC1_DATA_PORT, 0x0);
+ ioport_out(PIC2_DATA_PORT, 0x0);
+ // ICW4: "Gives additional information about the environemnt"
+ // See notes for some potential values
+ // We are using 8086/8088 (MCS-80/85) mode
+ // Not sure if that's relevant, but there it is.
+ // Other modes appear to be special slave/master configurations (see wiki)
+ ioport_out(PIC1_DATA_PORT, 0x1);
+ ioport_out(PIC2_DATA_PORT, 0x1);
+ // Voila! PICs are initialized
+
+ // Mask all interrupts (why? not entirely sure)
+ // 0xff is 16 bits that are all 1.
+ // This masks each of the 16 interrupts for that PIC.
+ ioport_out(PIC1_DATA_PORT, 0xff);
+ ioport_out(PIC2_DATA_PORT, 0xff);
+
+ init_idt_entry(0x21,(uint32_t)keyboard_handler,KERNEL_CODE,INTERRUPT_GATE_32);
+
+ idtp.size=sizeof(struct idt_entry)*256-1;
+ idtp.offset=(uint32_t)&idt;
+
+
+ load_idt(&idtp);
+}
diff --git a/src/c/kernel.c b/src/c/kernel.c
new file mode 100644
index 0000000..e18a7c0
--- /dev/null
+++ b/src/c/kernel.c
@@ -0,0 +1,17 @@
+#include"../include/heap.h"
+
+void terminal_initialize(void);
+void init_idt_table(void);
+void init_keyboard(void);
+void prompt(void);
+
+void kernel_main(void)
+{
+ terminal_initialize();
+ init_idt_table();
+ init_keyboard();
+ k_heapBMInit(&kheap);
+
+ prompt();
+ while(1) __asm__("hlt\n\t");
+}
diff --git a/src/c/keyboard.c b/src/c/keyboard.c
new file mode 100644
index 0000000..548cdda
--- /dev/null
+++ b/src/c/keyboard.c
@@ -0,0 +1,110 @@
+#include"../include/types.h"
+#include"../include/asm.h"
+#include"../include/stdio.h"
+
+#define BUFFER_SIZE 200
+char buffer[BUFFER_SIZE];
+size_t buffer_index=0;
+
+#define PIC1_COMMAND_PORT 0x20
+#define PIC1_DATA_PORT 0x21
+#define PIC2_COMMAND_PORT 0xA0
+#define PIC2_DATA_PORT 0xA1
+// IO Ports for Keyboard
+#define KEYBOARD_DATA_PORT 0x60
+#define KEYBOARD_STATUS_PORT 0x64
+
+void previous_field(void);
+void terminal_putchar(char c);
+void tty(char *buffer);
+void prompt(void);
+void clear();
+void us_en(char keymap[]);
+
+char charcode[256];
+bool ispressed[128];
+
+void init_keyboard()
+{
+ // 0xFD = 1111 1101 in binary. enables only IRQ1
+ // Why IRQ1? Remember, IRQ0 exists, it's 0-based
+ ioport_out(PIC1_DATA_PORT, 0xFD);
+ us_en(charcode);
+}
+
+void backspace()
+{
+ if(buffer_index<=0) return;
+
+ previous_field();
+ printf(" ");
+ previous_field();
+ buffer[--buffer_index]='\0';
+ return;
+}
+
+void enter()
+{
+ printf("\n");
+ if(buffer_index>0)
+ {
+ tty(buffer);
+ for(int i=0;i<BUFFER_SIZE;i++) buffer[i]='\0';
+ buffer_index=0;
+ }
+ prompt();
+ return;
+}
+
+void space()
+{
+ buffer[buffer_index++]=' ';
+ printf(" ");
+}
+#define lshift ispressed[0x2A]
+#define lctrl ispressed[0x1D]
+
+void handle_keyboard_interrupt()
+{
+ ioport_out(PIC1_COMMAND_PORT, 0x20);
+ uint8_t status = ioport_in(KEYBOARD_STATUS_PORT);
+
+ if (status & 0x1)
+ {
+ uint8_t keycode = ioport_in(KEYBOARD_DATA_PORT);
+ if(keycode<0x80)
+ {
+ ispressed[keycode]=1;
+ if(keycode==0x0E) backspace();
+ else if(keycode==0x1C) enter();
+ else if(keycode==0x39) space();
+ else
+ {
+ char c=charcode[keycode];
+ if(c!=' ')
+ {
+ if(lshift)
+ {
+ if(c>='a'&&c<='z') c-=32;
+ }
+ if(lctrl)
+ {
+ if(c=='l')
+ {
+ clear();
+ prompt();
+ return;
+ }
+ }
+ buffer[buffer_index++]=c;
+ printf("%c",c);
+ }
+ }
+ }
+ else
+ {
+ ispressed[keycode-0x80]=0;
+ }
+
+ }
+}
diff --git a/src/c/keymap.c b/src/c/keymap.c
new file mode 100644
index 0000000..04c79b2
--- /dev/null
+++ b/src/c/keymap.c
@@ -0,0 +1,173 @@
+void us_en(char keymap[])
+{
+ keymap[0x01]=' '; //escape pressed
+ keymap[0x02]='1'; //1 pressed
+ keymap[0x03]='2'; //2 pressed
+ keymap[0x04]='3'; //3 pressed
+ keymap[0x05]='4'; //4 pressed
+ keymap[0x06]='4'; //5 pressed
+ keymap[0x07]='5'; //6 pressed
+ keymap[0x08]='7'; //7 pressed
+ keymap[0x09]='8'; //8 pressed
+ keymap[0x0A]='9'; //9 pressed
+ keymap[0x0B]='0'; //0 (zero) pressed
+ keymap[0x0C]='-'; //- pressed
+ keymap[0x0D]='='; //= pressed
+ keymap[0x0E]=' '; //backspace pressed
+ keymap[0x0F]=' '; //tab pressed
+ keymap[0x10]='q'; //Q pressed
+ keymap[0x11]='w'; //W pressed
+ keymap[0x12]='e'; //E pressed
+ keymap[0x13]='r'; //R pressed
+ keymap[0x14]='t'; //T pressed
+ keymap[0x15]='y'; //Y pressed
+ keymap[0x16]='u'; //U pressed
+ keymap[0x17]='i'; //I pressed
+ keymap[0x18]='o'; //O pressed
+ keymap[0x19]='p'; //P pressed
+ keymap[0x1A]='['; //[ pressed
+ keymap[0x1B]=']'; //] pressed
+ keymap[0x1C]='\n'; //enter pressed
+ keymap[0x1D]=' '; //left control pressed
+ keymap[0x1E]='a'; //A pressed
+ keymap[0x1F]='s'; //S pressed
+ keymap[0x20]='d'; //D pressed
+ keymap[0x21]='f'; //F pressed
+ keymap[0x22]='g'; //G pressed
+ keymap[0x23]='h'; //H pressed
+ keymap[0x24]='j'; //J pressed
+ keymap[0x25]='k'; //K pressed
+ keymap[0x26]='l'; //L pressed
+ keymap[0x27]=';'; //; pressed
+ keymap[0x28]='\''; //' (single quote) pressed
+ keymap[0x29]='`'; //` (back tick) pressed
+ keymap[0x2A]=' '; //left shift pressed
+ keymap[0x2B]='\\'; //\ pressed
+ keymap[0x2C]='z'; //Z pressed
+ keymap[0x2D]='x'; //X pressed
+ keymap[0x2E]='c'; //C pressed
+ keymap[0x2F]='v'; //V pressed
+ keymap[0x30]='b'; //B pressed
+ keymap[0x31]='n'; //N pressed
+ keymap[0x32]='m'; //M pressed
+ keymap[0x33]=','; //, pressed
+ keymap[0x34]='.'; //. pressed
+ keymap[0x35]='/'; /// pressed
+ keymap[0x36]=' '; //right shift pressed
+ keymap[0x37]=' '; //(keypad) * pressed
+ keymap[0x38]=' '; //left alt pressed
+ keymap[0x39]=' '; //space pressed
+ keymap[0x3A]=' '; //CapsLock pressed
+ keymap[0x3B]=' '; //F1 pressed
+ keymap[0x3C]=' '; //F2 pressed
+ keymap[0x3D]=' '; //F3 pressed
+ keymap[0x3E]=' '; //F4 pressed
+ keymap[0x3F]=' '; //F5 pressed
+ keymap[0x40]=' '; //F6 pressed
+ keymap[0x41]=' '; //F7 pressed
+ keymap[0x42]=' '; //F8 pressed
+ keymap[0x43]=' '; //F9 pressed
+ keymap[0x44]=' '; //F10 pressed
+ keymap[0x45]=' '; //NumberLock pressed
+ keymap[0x46]=' '; //ScrollLock pressed
+ keymap[0x47]='7'; //(keypad) 7 pressed
+ keymap[0x48]='8'; //(keypad) 8 pressed
+ keymap[0x49]='9'; //(keypad) 9 pressed
+ keymap[0x4A]='-'; //(keypad) - pressed
+ keymap[0x4B]='4'; //(keypad) 4 pressed
+ keymap[0x4C]='5'; //(keypad) 5 pressed
+ keymap[0x4D]='6'; //(keypad) 6 pressed
+ keymap[0x4E]='+'; //(keypad) + pressed
+ keymap[0x4F]='1'; //(keypad) 1 pressed
+ keymap[0x50]='2'; //(keypad) 2 pressed
+ keymap[0x51]='3'; //(keypad) 3 pressed
+ keymap[0x52]='0'; //(keypad) 0 pressed
+ keymap[0x53]='.'; //(keypad) . pressed
+ keymap[0x57]=' '; //F11 pressed
+ keymap[0x58]=' '; //F12 pressed
+ keymap[0x81]=' '; //escape released
+ keymap[0x82]=' '; //1 released
+ keymap[0x83]=' '; //2 released
+ keymap[0x84]=' '; //3 released
+ keymap[0x85]=' '; //4 released
+ keymap[0x86]=' '; //5 released
+ keymap[0x87]=' '; //6 released
+ keymap[0x88]=' '; //7 released
+ keymap[0x89]=' '; //8 released
+ keymap[0x8A]=' '; //9 released
+ keymap[0x8B]=' '; //0 (zero) released
+ keymap[0x8C]=' '; //- released
+ keymap[0x8D]=' '; //= released
+ keymap[0x8E]=' '; //backspace released
+ keymap[0x8F]=' '; //tab released
+ keymap[0x90]=' '; //Q released
+ keymap[0x91]=' '; //W released
+ keymap[0x92]=' '; //E released
+ keymap[0x93]=' '; //R released
+ keymap[0x94]=' '; //T released
+ keymap[0x95]=' '; //Y released
+ keymap[0x96]=' '; //U released
+ keymap[0x97]=' '; //I released
+ keymap[0x98]=' '; //O released
+ keymap[0x99]=' '; //P released
+ keymap[0x9A]=' '; //[ released
+ keymap[0x9B]=' '; //] released
+ keymap[0x9C]=' '; //enter released
+ keymap[0x9D]=' '; //left control released
+ keymap[0x9E]=' '; //A released
+ keymap[0x9F]=' '; //S released
+ keymap[0xA0]=' '; //D released
+ keymap[0xA1]=' '; //F released
+ keymap[0xA2]=' '; //G released
+ keymap[0xA3]=' '; //H released
+ keymap[0xA4]=' '; //J released
+ keymap[0xA5]=' '; //K released
+ keymap[0xA6]=' '; //L released
+ keymap[0xA7]=' '; //; released
+ keymap[0xA8]=' '; //' (single quote) released
+ keymap[0xA9]=' '; //` (back tick) released
+ keymap[0xAA]=' '; //left shift released
+ keymap[0xAB]=' '; //\ released
+ keymap[0xAC]=' '; //Z released
+ keymap[0xAD]=' '; //X released
+ keymap[0xAE]=' '; //C released
+ keymap[0xAF]=' '; //V released
+ keymap[0xB0]=' '; //B released
+ keymap[0xB1]=' '; //N released
+ keymap[0xB2]=' '; //M released
+ keymap[0xB3]=' '; //, released
+ keymap[0xB4]=' '; //. released
+ keymap[0xB5]=' '; /// released
+ keymap[0xB6]=' '; //right shift released
+ keymap[0xB7]=' '; //(keypad) * released
+ keymap[0xB8]=' '; //left alt released
+ keymap[0xB9]=' '; //space released
+ keymap[0xBA]=' '; //CapsLock released
+ keymap[0xBB]=' '; //F1 released
+ keymap[0xBC]=' '; //F2 released
+ keymap[0xBD]=' '; //F3 released
+ keymap[0xBE]=' '; //F4 released
+ keymap[0xBF]=' '; //F5 released
+ keymap[0xC0]=' '; //F6 released
+ keymap[0xC1]=' '; //F7 released
+ keymap[0xC2]=' '; //F8 released
+ keymap[0xC3]=' '; //F9 released
+ keymap[0xC4]=' '; //F10 released
+ keymap[0xC5]=' '; //NumberLock released
+ keymap[0xC6]=' '; //ScrollLock released
+ keymap[0xC7]=' '; //(keypad) 7 released
+ keymap[0xC8]=' '; //(keypad) 8 released
+ keymap[0xC9]=' '; //(keypad) 9 released
+ keymap[0xCA]=' '; //(keypad) - released
+ keymap[0xCB]=' '; //(keypad) 4 released
+ keymap[0xCC]=' '; //(keypad) 5 released
+ keymap[0xCD]=' '; //(keypad) 6 released
+ keymap[0xCE]=' '; //(keypad) + released
+ keymap[0xCF]=' '; //(keypad) 1 released
+ keymap[0xD0]=' '; //(keypad) 2 released
+ keymap[0xD1]=' '; //(keypad) 3 released
+ keymap[0xD2]=' '; //(keypad) 0 released
+ keymap[0xD3]=' '; //(keypad) . released
+ keymap[0xD7]=' '; //F11 released
+ keymap[0xD8]=' '; //F12 released
+}
diff --git a/src/c/stdio.c b/src/c/stdio.c
new file mode 100644
index 0000000..83d2b0a
--- /dev/null
+++ b/src/c/stdio.c
@@ -0,0 +1,37 @@
+#include"../include/types.h"
+#include"../include/string.h"
+#include<stdarg.h>
+
+void terminal_putchar(char c);
+void terminal_writestring(char* data);
+void terminal_writeint(uint32_t data);
+void terminal_writefloat(double num);
+
+void printf(char *str, ...)
+{
+ size_t count=0;
+ for(size_t i=0;str[i]!='\0';i++) if(str[i]=='%') count++;
+
+ va_list list;
+ va_start(list, str);
+
+ for(size_t i=0;str[i]!='\0';i++)
+ {
+ if(str[i]=='%')
+ {
+ i++;
+ if(str[i]=='c') terminal_putchar((char)va_arg(list,int));
+ else if(str[i]=='s') terminal_writestring(va_arg(list,char*));
+ else if(str[i]=='d') terminal_writeint(va_arg(list,int));
+ else if(str[i]=='f') terminal_writefloat(va_arg(list,double));
+ else
+ {
+ terminal_writestring("wrong format using print function\n");
+ return;
+ }
+ }
+ else terminal_putchar(str[i]);
+ }
+
+ va_end(list);
+}
diff --git a/src/c/string.c b/src/c/string.c
new file mode 100644
index 0000000..5667715
--- /dev/null
+++ b/src/c/string.c
@@ -0,0 +1,113 @@
+#include"../include/types.h"
+
+size_t stringlen(char *str)
+{
+ size_t i;
+
+ for(i=0;str[i]!='\0';i++) ;
+
+ return i;
+}
+
+bool stringcmp(char *str1,char *str2)
+{
+ size_t i;
+ for(i=0;str1[i]||str2[i];i++) if(str1[i]!=str2[i]) return 0;
+ if(str1[i]==str2[i]) return 1;
+ return 0;
+}
+
+void stringcat(char *str1,char *str2)
+{
+ char *tmp=str1;
+ while(*tmp) tmp++;
+ while(*str2) *tmp++=*str2++;
+ *tmp=*str2;
+}
+
+void stringcpy(char *str1,char *str2)
+{
+ for(size_t i=0;str2[i]!='\0';i++) str1[i]=str2[i];
+}
+
+void stringrev(char *str)
+{
+ size_t i=stringlen(str)-1;
+
+ for(size_t j=0;j<i-j;j++)
+ {
+ char tmp=str[i-j];
+ str[i-j]=str[j];
+ str[j]=tmp;
+ }
+}
+
+uint32_t stoi(const char *str)
+{
+ uint32_t num=0;
+
+ for(size_t i=0;str[i]!='\0';i++)
+ {
+ if(str[i]<'0'||str[i]>'9') return num;
+ num*=10;
+ num+=str[i]-'0';
+ }
+
+ return num;
+}
+
+void itos(uint32_t num,char *str)
+{
+ if(num==0) stringcpy(str,"0");
+ else
+ {
+ size_t i=0;
+ for(;num>0;num/=10,i++) str[i]='0'+num%10;
+ str[i]='\0';
+
+ stringrev(str);
+ }
+}
+
+double stof(const char *str)
+{
+ double num=0;
+
+ bool point=0;
+ uint32_t pow=1;
+ size_t i=0;
+
+ for(;str[i]!='\0';i++)
+ {
+ if(str[i]=='.')
+ {
+ if(point) return num/pow;
+ point=1;
+ continue;
+ }
+ if(str[i]<'0'||str[i]>'9') return num/pow;
+ num*=10;
+ num+=str[i]-'0';
+ if(point) pow*=10;
+ }
+
+ return num/pow;
+}
+
+const int decimals=7;
+void ftos(double num, char *str)
+{
+ itos((uint32_t)num,str);
+
+ stringcat(str,".");
+ char c[2];
+ c[1]='\0';
+
+ for(size_t i=0;i<decimals;i++)
+ {
+ num-=(uint32_t)num;
+ num*=10;
+ c[0]=(uint32_t)num+'0';
+ stringcat(str,c);
+ }
+}
diff --git a/src/c/tty.c b/src/c/tty.c
new file mode 100644
index 0000000..5728a47
--- /dev/null
+++ b/src/c/tty.c
@@ -0,0 +1,75 @@
+#include"../include/types.h"
+#include"../include/string.h"
+#include"../include/stdio.h"
+
+#define CMD_LENGTH 20
+
+void clear();
+
+size_t pieces(char pieces[][CMD_LENGTH],char *buffer)
+{
+ for(size_t x=0;x<CMD_LENGTH;x++) for(size_t y=0;y<CMD_LENGTH;y++) pieces[x][y]='\0';
+
+ size_t i=0,j=0,r=0;
+ while(buffer[i]==' '&&buffer[i]!='\0') i++;
+ for(;buffer[i]!='\0';i++)
+ {
+ if(buffer[i]==' ')
+ {
+ while(buffer[i]==' '&&buffer[i]!='\0') i++;
+ j=0;
+ r++;
+ i--;
+ }
+ else
+ {
+ pieces[r][j++]=buffer[i];
+ }
+ }
+ return r+1;
+}
+
+void echo(size_t numberof,char parts[][CMD_LENGTH])
+{
+ for(size_t i=1;i<numberof;i++)
+ {
+ printf("%s ",parts[i]);
+ }
+ printf("\n");
+}
+
+void merge(char parts[][CMD_LENGTH])
+{
+ char *str1=parts[1];
+ char *str2=parts[2];
+ stringcat(str1,str2);
+ printf("%s\n",str1);
+}
+
+void ls(size_t numberof,char parts[][CMD_LENGTH])
+{
+ printf("filesystem not implemented yet, %d,%s\n",numberof,parts[0]);
+}
+
+void number(size_t numberof,char parts[][CMD_LENGTH])
+{
+ if(numberof==1) printf("Please enter a number\n");
+ else
+ {
+ printf("number times two is %d\n",2*stoi(parts[1]));
+ printf("number times two is %f\n",2*stof(parts[1]));
+ }
+}
+
+void tty(char *buffer)
+{
+ char parts[CMD_LENGTH][CMD_LENGTH];
+ size_t numberof=pieces(parts,buffer);
+
+ if(stringcmp(parts[0],"clear")) clear();
+ else if(stringcmp(parts[0],"echo")) echo(numberof,parts);
+ else if(stringcmp(parts[0],"merge")) merge(parts);
+ else if(stringcmp(parts[0],"ls")) ls(numberof,parts);
+ else if(stringcmp(parts[0],"number")) number(numberof,parts);
+ else printf("command not found: %s\n",parts[0]);
+}
diff --git a/src/c/vga.c b/src/c/vga.c
new file mode 100644
index 0000000..07dec60
--- /dev/null
+++ b/src/c/vga.c
@@ -0,0 +1,126 @@
+#include"../include/types.h"
+#include"../include/string.h"
+#include"../include/asm.h"
+
+static const size_t VGA_WIDTH = 80;
+static const size_t VGA_HEIGHT = 25;
+
+
+enum vga_color {
+ VGA_COLOR_BLACK = 0,
+ VGA_COLOR_BLUE = 1,
+ VGA_COLOR_GREEN = 2,
+ VGA_COLOR_CYAN = 3,
+ VGA_COLOR_RED = 4,
+ VGA_COLOR_MAGENTA = 5,
+ VGA_COLOR_BROWN = 6,
+ VGA_COLOR_LIGHT_GREY = 7,
+ VGA_COLOR_DARK_GREY = 8,
+ VGA_COLOR_LIGHT_BLUE = 9,
+ VGA_COLOR_LIGHT_GREEN = 10,
+ VGA_COLOR_LIGHT_CYAN = 11,
+ VGA_COLOR_LIGHT_RED = 12,
+ VGA_COLOR_LIGHT_MAGENTA = 13,
+ VGA_COLOR_LIGHT_BROWN = 14,
+ VGA_COLOR_WHITE = 15,
+};
+
+static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
+{
+ return fg | bg << 4;
+}
+
+static inline uint16_t vga_entry(unsigned char uc, uint8_t color)
+{
+ return (uint16_t) uc | (uint16_t) color << 8;
+}
+
+size_t terminal_row;
+size_t terminal_column;
+uint8_t terminal_color;
+uint16_t* terminal_buffer;
+
+void terminal_initialize()
+{
+ terminal_row=0;
+ terminal_column=0;
+ terminal_color=vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
+ terminal_buffer=(uint16_t*) 0xB8000;
+ for(size_t y=0;y<VGA_HEIGHT;y++)
+ {
+ for(size_t x=0;x<VGA_WIDTH;x++)
+ {
+ const size_t index=y*VGA_WIDTH+x;
+ terminal_buffer[index]=vga_entry(' ', terminal_color);
+ }
+ }
+}
+
+void terminal_putentryat(char c, uint8_t color, size_t x, size_t y)
+{
+ const size_t index=y*VGA_WIDTH+x;
+ terminal_buffer[index]=vga_entry(c, color);
+}
+
+void movescreen()
+{
+ terminal_row--;
+ for(size_t i=0;i<VGA_HEIGHT;i++) for(size_t j=0;j<VGA_WIDTH;j++) terminal_buffer[i*VGA_WIDTH+j]=terminal_buffer[(i+1)*VGA_WIDTH+j];
+}
+
+void next_field()
+{
+ if(++terminal_column==VGA_WIDTH) terminal_column=0,terminal_row++;
+}
+
+void previous_field()
+{
+ if(terminal_column) terminal_column--;
+ else terminal_row--,terminal_column=VGA_WIDTH-1;
+}
+
+void terminal_putchar(char c)
+{
+ if(c=='\n') terminal_column=0,terminal_row++;
+ else
+ {
+ terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
+ next_field();
+ }
+ if (terminal_row==VGA_HEIGHT) movescreen();
+}
+
+void terminal_writestring(char* data)
+{
+ for(int i=0;data[i]!='\0';i++) terminal_putchar(data[i]);
+}
+
+void terminal_writeint(uint32_t num)
+{
+ char string[100];
+ for(int i=0;i<100;i++) string[i]='\0';
+ char *str=string;
+ itos(num,str);
+ terminal_writestring(str);
+}
+
+void terminal_writefloat(double num)
+{
+ char string[100];
+ for(int i=0;i<100;i++) string[i]='\0';
+ char *str=string;
+ ftos(num,str);
+ terminal_writestring(str);
+}
+
+void prompt()
+{
+ terminal_writestring("[user@myos] > ");
+}
+
+void clear()
+{
+ for(size_t i=0;i<VGA_HEIGHT;i++) for(size_t j=0;j<VGA_WIDTH;j++) terminal_putchar(' ');
+ terminal_column=0;
+ terminal_row=0;
+}