diff --git a/.gitignore b/.gitignore index fb98d2c..c13f0bc 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ # Compiled Object files *.slo *.lo -*.o +#*.o *.obj # Precompiled Headers diff --git a/compile.bat b/compile.bat new file mode 100644 index 0000000..8b34431 --- /dev/null +++ b/compile.bat @@ -0,0 +1,22 @@ +@echo off +rem The name of the loader assembly file (without extension, must be .asm): +set loader_name=loader + +rem NASM and DJGPP executable paths: +set nasm_path=C:\nasm +set djgpp_path=C:\DJGPP\bin + +@echo on +rem Compile loader +%nasm_path%\nasm.exe -f aout -o %loader_name%.o %loader_name%.asm +rem Compile main Kernel +%djgpp_path%\gcc.exe -Wall -O -fstrength-reduce -fomit-frame-pointer -finline-functions -nostdinc -fno-builtin -I./include -c -o main.o main.c +rem OTHER GCC/NASM SOURCES GO HERE + +@echo on +%djgpp_path%\ld -T link.ld -o kernel.bin %loader_name%.o main.o +@echo . +@echo Done! + +@pause +copy C:\CTAOS\KERNEL.BIN C:\SHARE diff --git a/console.o b/console.o new file mode 100644 index 0000000..33bd1c5 Binary files /dev/null and b/console.o differ diff --git a/gdt.c b/gdt.c new file mode 100644 index 0000000..12638ec --- /dev/null +++ b/gdt.c @@ -0,0 +1,78 @@ +#include + +/* Defines a GDT entry. We say packed, because it prevents the +* compiler from doing things that it thinks is best: Prevent +* compiler "optimization" by packing */ +struct gdt_entry +{ + unsigned short limit_low; + unsigned short base_low; + unsigned char base_middle; + unsigned char access; + unsigned char granularity; + unsigned char base_high; +} __attribute__((packed)); + +/* Special pointer which includes the limit: The max bytes +* taken up by the GDT, minus 1. Again, this NEEDS to be packed */ +struct gdt_ptr +{ + unsigned short limit; + unsigned int base; +} __attribute__((packed)); + +/* Our GDT, with 3 entries, and finally our special GDT pointer */ +struct gdt_entry gdt[3]; +struct gdt_ptr gp; + +/* This will be a function in start.asm. We use this to properly +* reload the new segment registers */ +extern void gdt_flush(); + +/* Setup a descriptor in the Global Descriptor Table */ +void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran) +{ + /* Setup the descriptor base address */ + gdt[num].base_low = (base & 0xFFFF); + gdt[num].base_middle = (base >> 16) & 0xFF; + gdt[num].base_high = (base >> 24) & 0xFF; + + /* Setup the descriptor limits */ + gdt[num].limit_low = (limit & 0xFFFF); + gdt[num].granularity = ((limit >> 16) & 0x0F); + + /* Finally, set up the granularity and access flags */ + gdt[num].granularity |= (gran & 0xF0); + gdt[num].access = access; +} + +/* Should be called by main. This will setup the special GDT +* pointer, set up the first 3 entries in our GDT, and then +* finally call gdt_flush() in our assembler file in order +* to tell the processor where the new GDT is and update the +* new segment registers */ +void gdt_install() +{ + /* Setup the GDT pointer and limit */ + gp.limit = (sizeof(struct gdt_entry) * 3) - 1; + gp.base = &gdt; + + /* Our NULL descriptor */ + gdt_set_gate(0, 0, 0, 0, 0); + + /* The second entry is our Code Segment. The base address + * is 0, the limit is 4GBytes, it uses 4KByte granularity, + * uses 32-bit opcodes, and is a Code Segment descriptor. + * Please check the table above in the tutorial in order + * to see exactly what each value means */ + gdt_set_gate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); + + /* The third entry is our Data Segment. It's EXACTLY the + * same as our code segment, but the descriptor type in + * this entry's access byte says it's a Data Segment */ + gdt_set_gate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); + + /* Flush out the old GDT and install the new changes! */ + gdt_flush(); +} + \ No newline at end of file diff --git a/idt.c b/idt.c new file mode 100644 index 0000000..e719dec --- /dev/null +++ b/idt.c @@ -0,0 +1,62 @@ +#include + +/* Defines an IDT entry */ +struct idt_entry +{ + unsigned short base_lo; + unsigned short sel; + unsigned char always0; + unsigned char flags; + unsigned short base_hi; +} __attribute__((packed)); + +struct idt_ptr +{ + unsigned short limit; + unsigned int base; +} __attribute__((packed)); + +/* Declare an IDT of 256 entries. Although we will only use the +* first 32 entries in this tutorial, the rest exists as a bit +* of a trap. If any undefined IDT entry is hit, it normally +* will cause an "Unhandled Interrupt" exception. Any descriptor +* for which the 'presence' bit is cleared (0) will generate an +* "Unhandled Interrupt" exception */ +struct idt_entry idt[256]; +struct idt_ptr idtp; + +/* This exists in 'start.asm', and is used to load our IDT */ +extern void idt_load(); + +/* Use this function to set an entry in the IDT. Alot simpler +* than twiddling with the GDT ;) */ +void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags) +{ + /* The interrupt routine's base address */ + idt[num].base_lo = (base & 0xFFFF); + idt[num].base_hi = (base >> 16) & 0xFFFF; + + /* The segment or 'selector' that this IDT entry will use + * is set here, along with any access flags */ + idt[num].sel = sel; + idt[num].always0 = 0; + idt[num].flags = flags; +} + +/* Installs the IDT */ +void idt_install() +{ + /* Sets the special IDT pointer up, just like in 'gdt.c' */ + idtp.limit = (sizeof (struct idt_entry) * 256) - 1; + idtp.base = &idt; + + /* Clear out the entire IDT, initializing it to zeros */ + memset(&idt, 0, sizeof(struct idt_entry) * 256); + + /* Add any new ISRs to the IDT here using idt_set_gate */ + + + + /* Points the processor's internal register to the new IDT */ + idt_load(); +} diff --git a/include/console.h b/include/console.h new file mode 100644 index 0000000..4630fe8 --- /dev/null +++ b/include/console.h @@ -0,0 +1,152 @@ +#include + +#ifndef __CONSOLE_H +#define __CONSOLE_H +#define _ATTRIB 0x0F + +byte default_background, default_foreground; + + +// Change cursor position +void text_mode_cursor(int x, int y) +{ + unsigned temp = y*current_mode_width + x; + + outportb (0x3D4, 14); + outportb (0x3D5, temp >> 8); + outportb (0x3D4, 15); + outportb (0x3D5, temp); +} + +// Set the default colors; max is 0x0F +void set_default_colors(byte back, byte fore) +{ + if (back < 0x10) default_background = back; + if (fore < 0x10) default_foreground = fore; +} + + +// Clear screen, and set font to default font +void clrscr() +{ + byte font = default_foreground | (default_background<<4); + int i = 0; + for (i = 0; i < current_mode_width*current_mode_height; i++) + { TextVideoRam[2*i] = 0; + TextVideoRam[2*i+1] = font; + } + cursor_x = 0; cursor_y = 0; +} + +void scroll(int n) +{ + memcpy(TextVideoRam, + TextVideoRam+(current_mode_width*n*2), + 2*current_mode_width*(current_mode_height - n)); + + byte blank = default_foreground | (default_background<<4); + + int i; + for (i = current_mode_width*(current_mode_height-n); + i < current_mode_width*current_mode_height; i++){ + TextVideoRam[2*i] = 0; + TextVideoRam[2*i+1] = blank; + } +} + + +void _endl() +{ + cursor_x = 0; + if (++cursor_y >=25) { + cursor_y = 24; scroll(1); + } +} + + +// Put character on screen in specified position; can use different font colors +void putc_pos_font(int x, int y, char c, byte back, byte fore) +{ + TextVideoRam[2*(y*current_mode_width+x)] = c; + TextVideoRam[2*(y*current_mode_width+x)+1] = fore|(back<<4); +} +// Put character on screen in specified position; use default font colors +void putc_pos(int x, int y, char c) +{ + TextVideoRam[2*(y*current_mode_width+x)] = c; +} +// Put character on screen in the current cursor position; different font colors +void putc_font(char c, byte back, byte fore) +{ + if (cursor_x > current_mode_width) _endl(); + + if (c == '\n') {_endl(); return;}; + TextVideoRam[2*(cursor_y*current_mode_width+cursor_x)] = c; + TextVideoRam[2*(cursor_y*current_mode_width+cursor_x)+1] = fore|(back<<4); + cursor_x++; +} +// Put character on screen in the current cursor position; default font colors +void putc(char c) +{ + if (cursor_x > current_mode_width) _endl(); + + if (c == '\n') {_endl(); return;}; + TextVideoRam[2*(cursor_y*current_mode_width+cursor_x)] = c; + cursor_x++; +} + +// Put string on screen in specified position; can use different font colors +void puts_pos_font(int x, int y, char *str, byte back, byte fore) +{ + int i; + for (i = 0; str[i] != 0; i++) + putc_pos_font(x+i, y, str[i], back, fore); + +} + +// Put string on screen in specified position; use default font colors +void puts_pos(int x, int y, char *str) +{ + int i; + for (i = 0; str[i] != 0; i++) + putc_pos(x+i, y, str[i]); +} +void puts(char *str) +{ + int i; + for (i = 0; str[i] != 0; i++) + putc(str[i]); +} + +void puts_font(char *str, byte back, byte fore) +{ + int i; + for (i = 0; str[i] != 0; i++) + putc_font(str[i], back, fore); +} + +void put_hex(int x, int y, unsigned int alpha) +{ + char hex[] = "0123456789ABCDEF"; + char nr[9]; + int i; + for (i = 7; i >= 0; i--) { + nr[i] = hex[alpha%16]; + alpha /= 16; + } + nr[8] = 0; + puts_pos(x, y, nr); +} + +void put_bin (int x, int y, byte xz) +{ + int i; + char arr[9] = {0,0,0,0,0,0,0,0,0}; + for(i=7; i>=0; i--) { + arr[i] = (xz%2) + '0'; xz/=2; + } + puts_pos (x, y, arr); +} + + +#endif \ No newline at end of file diff --git a/include/system.h b/include/system.h new file mode 100644 index 0000000..87af581 --- /dev/null +++ b/include/system.h @@ -0,0 +1,104 @@ +#ifndef __SYSTEM_H +#define __SYSTEM_H + +// Data type declarations +typedef unsigned char byte; +typedef unsigned short word; +typedef unsigned int dword; + +/* This defines what the stack looks like after an ISR was running */ +typedef struct +{ + unsigned int gs, fs, es, ds; /* pushed the segs last */ + unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; /* pushed by 'pusha' */ + unsigned int int_no, err_code; /* our 'push byte #' and ecodes do this */ + unsigned int eip, cs, eflags, useresp, ss; /* pushed by the processor automatically */ +} regs; + + +byte *TextVideoRam; +int cursor_x, cursor_y; +int current_mode_width; +int current_mode_height; + +// System functions declaration +void system_init(); +void *memcpy(void *dest, const void *src, int count); +void *memset(void *dest, char val, int count); +unsigned short *memsetw(unsigned short *dest, unsigned short val, int count); +int strlen (const char *str); +byte inportb (word _port); +byte inb (word _port); +void outportb (word _port, byte _data); +void outb (word _port, byte _data) ; + +// GDT, IDT, ISRs, IRQ functions declarations +void gdt_set_gate(int num, unsigned long base, unsigned long limit, unsigned char access, unsigned char gran); +void gdt_install(); + +void idt_set_gate(unsigned char num, unsigned long base, unsigned short sel, unsigned char flags); +void idt_install(); + +void isrs_install(); + +void irq_install_handler(int irq, void (*handler)(regs *r)); +void irq_uninstall_handler(int irq); +void irq_install(); + + +// Initialize system + + +void *memcpy(void *dest, const void *src, int count) +{ + const char *sp = (const char *)src; + char *dp = (char *)dest; + for(; count != 0; count--) *dp++ = *sp++; + return dest; +} + +void *memset(void *dest, char val, int count) +{ + char *temp = (char *)dest; + for( ; count != 0; count--) *temp++ = val; + return dest; +} + +unsigned short *memsetw(unsigned short *dest, unsigned short val, int count) +{ + unsigned short *temp = (unsigned short *)dest; + for( ; count != 0; count--) *temp++ = val; + return dest; +} + + +// strlen -- Get lenght of str +int strlen (const char *str) +{ + int i; + for (i = 0; str[i]!=0; i++) {} + return i; +} + + +byte inportb (word _port) { + byte rv; + __asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port)); + return rv; +} +byte inb (word _port) { + byte rv; + __asm__ __volatile__ ("inb %1, %0" : "=a" (rv) : "dN" (_port)); + return rv; +} + + +void outportb (word _port, byte _data) { + __asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data)); +} +void outb (word _port, byte _data) { + __asm__ __volatile__ ("outb %1, %0" : : "dN" (_port), "a" (_data)); +} + + +#endif \ No newline at end of file diff --git a/init.c b/init.c new file mode 100644 index 0000000..9dcd6ef --- /dev/null +++ b/init.c @@ -0,0 +1,37 @@ +#include + + +void system_init() +{ + // Detect if color/monochrome screen + char c = (*(volatile unsigned short*)0x410)&0x30; + if (c==0x30) TextVideoRam = (byte *)0xb0000; + else TextVideoRam = (byte *)0xb8000; + + // Reset cursor, use 80x25 text video mode + current_mode_width = 80; + current_mode_height = 25; + cursor_x = cursor_y = 0; + + // Install GDT, IDT, ISRs and IRQs; Enable interrupts + gdt_install(); + idt_install(); + isrs_install(); + irq_install(); + __asm__ __volatile__ ("sti"); + + // Install PIT timer + timer_ticks = 0; + irq_install_handler(0, timer_handler); + timer_phase (100); + + // Install keyboard + kb_modifier_status = 0; + kb_lights_status = 0xFF; kb_update_LED(); + kb_lights_status = 0; kb_update_LED(); + irq_install_handler(1, kb_handler); + + // mouse_driver(); + + +} \ No newline at end of file diff --git a/irq.c b/irq.c new file mode 100644 index 0000000..4c1e861 --- /dev/null +++ b/irq.c @@ -0,0 +1,118 @@ +#include + +/* These are own ISRs that point to our special IRQ handler +* instead of the regular 'fault_handler' function */ + +extern void irq0(); +extern void irq1(); +extern void irq2(); +extern void irq3(); +extern void irq4(); +extern void irq5(); +extern void irq6(); +extern void irq7(); +extern void irq8(); +extern void irq9(); +extern void irq10(); +extern void irq11(); +extern void irq12(); +extern void irq13(); +extern void irq14(); +extern void irq15(); + +/* This array is actually an array of function pointers. We use +* this to handle custom IRQ handlers for a given IRQ */ +void *irq_routines[16] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* This installs a custom IRQ handler for the given IRQ */ +void irq_install_handler (int irq, void (*handler)(regs *r)) +{ + irq_routines[irq] = handler; +} + +void irq_uninstall_handler (int irq) +{ + irq_routines[irq] = 0; +} + + +/* Normally, IRQs 0 to 7 are mapped to entries 8 to 15. This +* is a problem in protected mode, because IDT entry 8 is a +* Double Fault! Without remapping, every time IRQ0 fires, +* you get a Double Fault Exception, which is NOT actually +* what's happening. We send commands to the Programmable +* Interrupt Controller (PICs - also called the 8259's) in +* order to make IRQ0 to 15 be remapped to IDT entries 32 to +* 47 */ +void irq_remap(void) +{ + outportb(0x20, 0x11); + outportb(0xA0, 0x11); + outportb(0x21, 0x20); + outportb(0xA1, 0x28); + outportb(0x21, 0x04); + outportb(0xA1, 0x02); + outportb(0x21, 0x01); + outportb(0xA1, 0x01); + outportb(0x21, 0x0); + outportb(0xA1, 0x0); +} + +/* We first remap the interrupt controllers, and then we install +* the appropriate ISRs to the correct entries in the IDT. This +* is just like installing the exception handlers */ +void irq_install() +{ + irq_remap(); + + idt_set_gate(32, (unsigned)irq0, 0x08, 0x8E); + idt_set_gate(33, (unsigned)irq1, 0x08, 0x8E); + idt_set_gate(34, (unsigned)irq2, 0x08, 0x8E); + idt_set_gate(35, (unsigned)irq3, 0x08, 0x8E); + idt_set_gate(36, (unsigned)irq4, 0x08, 0x8E); + idt_set_gate(37, (unsigned)irq5, 0x08, 0x8E); + idt_set_gate(38, (unsigned)irq6, 0x08, 0x8E); + idt_set_gate(39, (unsigned)irq7, 0x08, 0x8E); + idt_set_gate(40, (unsigned)irq8, 0x08, 0x8E); + idt_set_gate(41, (unsigned)irq9, 0x08, 0x8E); + idt_set_gate(42, (unsigned)irq10, 0x08, 0x8E); + idt_set_gate(43, (unsigned)irq11, 0x08, 0x8E); + idt_set_gate(44, (unsigned)irq12, 0x08, 0x8E); + idt_set_gate(45, (unsigned)irq13, 0x08, 0x8E); + idt_set_gate(46, (unsigned)irq14, 0x08, 0x8E); + idt_set_gate(47, (unsigned)irq15, 0x08, 0x8E); +} + +/* Each of the IRQ ISRs point to this function, rather than +* the 'fault_handler' in 'isrs.c'. The IRQ Controllers need +* to be told when you are done servicing them, so you need +* to send them an "End of Interrupt" command (0x20). There +* are two 8259 chips: The first exists at 0x20, the second +* exists at 0xA0. If the second controller (an IRQ from 8 to +* 15) gets an interrupt, you need to acknowledge the +* interrupt at BOTH controllers, otherwise, you only send +* an EOI command to the first controller. If you don't send +* an EOI, you won't raise any more IRQs */ +void irq_handler (regs *r) +{ + /* This is a blank function pointer */ + void (*handler)(regs *r); + + /* Find out if we have a custom handler to run for this + * IRQ, and then finally, run it */ + handler = irq_routines[r->int_no - 32]; + if (handler) handler(r); + + /* If the IDT entry that was invoked was greater than 40 + * (meaning IRQ8 - 15), then we need to send an EOI to + * the slave controller */ + if (r->int_no >=40) outportb(0x0A, 0x20); + + /* In either case, we need to send an EOI to the master + * interrupt controller too */ + outportb(0x20, 0x20); +} diff --git a/isrs.c b/isrs.c new file mode 100644 index 0000000..cf975eb --- /dev/null +++ b/isrs.c @@ -0,0 +1,163 @@ +#include +#include + +extern void isr0(); +extern void isr1(); +extern void isr2(); +extern void isr3(); +extern void isr4(); +extern void isr5(); +extern void isr6(); +extern void isr7(); +extern void isr8(); +extern void isr9(); +extern void isr10(); +extern void isr11(); +extern void isr12(); +extern void isr13(); +extern void isr14(); +extern void isr15(); +extern void isr16(); +extern void isr17(); +extern void isr18(); +extern void isr19(); +extern void isr20(); +extern void isr21(); +extern void isr22(); +extern void isr23(); +extern void isr24(); +extern void isr25(); +extern void isr26(); +extern void isr27(); +extern void isr28(); +extern void isr29(); +extern void isr30(); +extern void isr31(); + +/* This is a very repetitive function... it's not hard, it's +* just annoying. As you can see, we set the first 32 entries +* in the IDT to the first 32 ISRs. We can't use a for loop +* for this, because there is no way to get the function names +* that correspond to that given entry. We set the access +* flags to 0x8E. This means that the entry is present, is +* running in ring 0 (kernel level), and has the lower 5 bits +* set to the required '14', which is represented by 'E' in +* hex. */ +void isrs_install() +{ + idt_set_gate(0, (unsigned)isr0, 0x08, 0x8E); + idt_set_gate(1, (unsigned)isr1, 0x08, 0x8E); + idt_set_gate(2, (unsigned)isr2, 0x08, 0x8E); + idt_set_gate(3, (unsigned)isr3, 0x08, 0x8E); + idt_set_gate(4, (unsigned)isr4, 0x08, 0x8E); + idt_set_gate(5, (unsigned)isr5, 0x08, 0x8E); + idt_set_gate(6, (unsigned)isr6, 0x08, 0x8E); + idt_set_gate(7, (unsigned)isr7, 0x08, 0x8E); + idt_set_gate(8, (unsigned)isr8, 0x08, 0x8E); + idt_set_gate(9, (unsigned)isr9, 0x08, 0x8E); + idt_set_gate(10, (unsigned)isr10, 0x08, 0x8E); + idt_set_gate(11, (unsigned)isr11, 0x08, 0x8E); + idt_set_gate(12, (unsigned)isr12, 0x08, 0x8E); + idt_set_gate(13, (unsigned)isr13, 0x08, 0x8E); + idt_set_gate(14, (unsigned)isr14, 0x08, 0x8E); + idt_set_gate(15, (unsigned)isr15, 0x08, 0x8E); + idt_set_gate(16, (unsigned)isr16, 0x08, 0x8E); + idt_set_gate(17, (unsigned)isr17, 0x08, 0x8E); + idt_set_gate(18, (unsigned)isr18, 0x08, 0x8E); + idt_set_gate(19, (unsigned)isr19, 0x08, 0x8E); + idt_set_gate(20, (unsigned)isr20, 0x08, 0x8E); + idt_set_gate(21, (unsigned)isr21, 0x08, 0x8E); + idt_set_gate(22, (unsigned)isr22, 0x08, 0x8E); + idt_set_gate(23, (unsigned)isr23, 0x08, 0x8E); + idt_set_gate(24, (unsigned)isr24, 0x08, 0x8E); + idt_set_gate(25, (unsigned)isr25, 0x08, 0x8E); + idt_set_gate(26, (unsigned)isr26, 0x08, 0x8E); + idt_set_gate(27, (unsigned)isr27, 0x08, 0x8E); + idt_set_gate(28, (unsigned)isr28, 0x08, 0x8E); + idt_set_gate(29, (unsigned)isr29, 0x08, 0x8E); + idt_set_gate(30, (unsigned)isr30, 0x08, 0x8E); + idt_set_gate(31, (unsigned)isr31, 0x08, 0x8E); +} + + char *exception_messages[] = { + "Division By Zero Exception", + "Debug Exception", + "Non Maskable Interrupt Exception", + "Breakpoint Exception", + "Into Detected Overflow Exception", + "Out of Bounds Exception", + "Invalid Opcode Exception", + "No Coprocessor", + "Double Fault Exception", + "Coprocessor Segment Overrun Exception", + "Bad TSS Exception", + "Segment Not Present Exception", + "Stack Fault Exception", + "General Protection Fault Exception", + "Page Fault Exception", + "Unknown Interrupt Exception", + "Coprocessor Fault Exception", + "Alignment Check Exception", + "Machine Check Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception", + "Reserved Exception" +}; + + +/* All of our Exception handling Interrupt Service Routines will +* point to this function. This will tell us what exception has +* happened! Right now, we simply halt the system by hitting an +* endless loop. All ISRs disable interrupts while they are being +* serviced as a 'locking' mechanism to prevent an IRQ from +* happening and messing up kernel data structures */ +void fault_handler(regs *r) +{ + /* Is this a fault whose number is from 0 to 31? */ + if (r->int_no < 32) + { + /* Display the description for the Exception that occurred.*/ + + // Put on the BSOD screen + set_default_colors (0x01, 0x0F); clrscr(); + puts (" Blue Screen Of Death\n"); + int i; for (i = 79; i>=0; i--) putc('='); + puts_pos_font (15, 2, "A fatal error has occured, CTA OS has been halted.", 0x01, 0x0C); + puts_pos_font (10, 4, "gs", 0x01, 0x0B); put_hex(15, 4, r->gs); + puts_pos_font (10, 5, "fs", 0x01, 0x0B); put_hex(15, 5, r->fs); + puts_pos_font (10, 6, "es", 0x01, 0x0B); put_hex(15, 6, r->es); + puts_pos_font (10, 7, "ds", 0x01, 0x0B); put_hex(15, 7, r->ds); + + puts_pos_font (40, 4, "edi", 0x01, 0x0B); put_hex(45, 4, r->edi); + puts_pos_font (40, 5, "esi", 0x01, 0x0B); put_hex(45, 5, r->esi); + puts_pos_font (40, 6, "ebp", 0x01, 0x0B); put_hex(45, 6, r->ebp); + puts_pos_font (40, 7, "esp", 0x01, 0x0B); put_hex(45, 7, r->esp); + + puts_pos_font (10, 9, "eax", 0x01, 0x0B); put_hex(15, 9, r->eax); + puts_pos_font (10, 10, "ebx", 0x01, 0x0B); put_hex(15, 10, r->ebx); + puts_pos_font (40, 9, "ecx", 0x01, 0x0B); put_hex(45, 9, r->ecx); + puts_pos_font (40, 10, "edx", 0x01, 0x0B); put_hex(45, 10, r->edx); + + puts_pos_font (10, 12, "int_no", 0x01, 0x0B); put_hex(17, 12, r->int_no); + puts_pos_font (10, 14, "Error code:", 0x01, 0x0B); put_hex(24, 14, r->err_code); + puts_pos_font (10, 15, "Error msg: ", 0x01, 0x0B); puts_pos(24, 15, exception_messages[r->int_no]); + + puts_pos_font (10, 17, "eip", 0x01, 0x0B); put_hex(17, 17, r->eip); + puts_pos_font (10, 18, "cs", 0x01, 0x0B); put_hex(17, 18, r->cs); + puts_pos_font (10, 19, "eflags", 0x01, 0x0B); put_hex(17, 19, r->eflags); + puts_pos_font (10, 20, "useresp", 0x01, 0x0B); put_hex(17, 20, r->useresp); + puts_pos_font (10, 21, "ss", 0x01, 0x0B); put_hex(17, 21, r->ss); + + puts_pos_font (29, 24, "!!! System Halted !!!", 0x01, 0x0C); + for (;;); + } +} diff --git a/kernel.bin b/kernel.bin new file mode 100644 index 0000000..cb04e41 Binary files /dev/null and b/kernel.bin differ diff --git a/keyus.c b/keyus.c new file mode 100644 index 0000000..879a9ea --- /dev/null +++ b/keyus.c @@ -0,0 +1,209 @@ +unsigned char kbdus[128] = +{ + 0, 27, '1', '2', '3', '4', '5', '6', '7', '8', /* 9 */ + '9', '0', '-', '=', '\b', /* Backspace */ + '\t', /* Tab */ + 'q', 'w', 'e', 'r', /* 19 */ + 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\n', /* Enter key */ + 0, /* 29 - Control */ + 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', /* 39 */ + '\'', '`', 0, /* Left shift */ + '\\', 'z', 'x', 'c', 'v', 'b', 'n', /* 49 */ + 'm', ',', '.', '/', 0, /* Right shift */ + '*', + 0, /* Alt */ + ' ', /* Space bar */ + 0, /* Caps lock */ + 0, /* 59 - F1 key ... > */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* < ... F10 */ + 0, /* 69 - Num lock*/ + 0, /* Scroll Lock */ + 0, /* Home key */ + 0, /* Up Arrow */ + 0, /* Page Up */ + '-', + 0, /* Left Arrow */ + 0, + 0, /* Right Arrow */ + '+', + 0, /* 79 - End key*/ + 0, /* Down Arrow */ + 0, /* Page Down */ + 0, /* Insert Key */ + 0, /* Delete Key */ + 0, 0, 0, + 0, /* F11 Key */ + 0, /* F12 Key */ + 0, /* All other keys are undefined */ +}; + +unsigned char kbdus_shift[128] = +{ + 0, 27, '!', '@', '#', '$', '%', '^', '&', '*', /* 9 */ + '(', ')', '_', '+', '\b', /* Backspace */ + '\t', /* Tab */ + 'Q', 'W', 'E', 'R', /* 19 */ + 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', '\n', /* Enter key */ + 0, /* 29 - Control */ + 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', /* 39 */ + '\"', '~', 0, /* Left shift */ + '|', 'Z', 'X', 'C', 'V', 'B', 'N', /* 49 */ + 'M', '<', '>', '?', 0, /* Right shift */ + '*', + 0, /* Alt */ + ' ', /* Space bar */ + 0, /* Caps lock */ + 0, /* 59 - F1 key ... > */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* < ... F10 */ + 0, /* 69 - Num lock*/ + 0, /* Scroll Lock */ + 0, /* Home key */ + 0, /* Up Arrow */ + 0, /* Page Up */ + '-', + 0, /* Left Arrow */ + 0, + 0, /* Right Arrow */ + '+', + 0, /* 79 - End key*/ + 0, /* Down Arrow */ + 0, /* Page Down */ + 0, /* Insert Key */ + 0, /* Delete Key */ + 0, 0, 0, + 0, /* F11 Key */ + 0, /* F12 Key */ + 0, /* All other keys are undefined */ +}; + + + +/* kb_modifier_status: + BIT | Description + ----+----------------------------------- + 0 | Left Shift + 1 | Right Shift + 2 | Left Alt + 3 | Right Alt + 4 | Left CTRL + 5 | Right CTRL + 6 | Fake Shift + 7 | Special */ +unsigned char kb_modifier_status; + +/* kb_lights_status + BIT | Description + ----+----------------------------------- + 0 | SCROLLOCK + 1 | NUMLOCK + 2 | CAPSLOCK */ +unsigned char kb_lights_status; + +void kb_update_LED() +{ + while ((inportb (0x64)&2)!=0); + outportb (0x60, 0xED); + + while ((inportb (0x64)&2)!=0); + outportb (0x60, kb_lights_status); +} + +/* kb_toggle_LED + Toggle NUM/CAPS/SCROLL LOCK LEDs. 0 to ignore. If all 0, reset; */ +void kb_toggle_LED(int NUM, int CAPS, int SCROLL) +{ + if (NUM) kb_lights_status ^= 1<<1; + if (CAPS) kb_lights_status ^= 1<<2; + if (SCROLL) kb_lights_status ^= 1; + if ((!NUM) && (!CAPS) && (!SCROLL)) kb_lights_status = 0; + kb_update_LED(); +} + +byte prev, scancode; +void kb_handler(regs *r) { + scancode = inportb(0x60); + + puts_pos(0, 0, "Key Pressed ");put_hex(30, 0, scancode); + + switch (scancode) { + // Special + case 0x0E: kb_modifier_status |= 1<<7; + break; + + // Left Shift or fake shift make + case 0x2A: if (kb_modifier_status && 128) kb_modifier_status |= 1<<6; + else kb_modifier_status |= 1; + break; + + // Left Shift or fake shift release + case 0xAA: if (kb_modifier_status && 128) kb_modifier_status &= (1<<6) ^0xFF; + else kb_modifier_status &= 1 ^0xFF; + break; + + // Right Shift make + case 0x36: kb_modifier_status |= 1<<1; + break; + + // Right shift release + case 0xB6: kb_modifier_status &= (1<<1) ^0xFF; + break; + + // Left Alt or Right Alt make + case 0x38: if (kb_modifier_status && 128) kb_modifier_status |= 1<<3; + else kb_modifier_status |= 1<<2; + break; + + // Left Alt or Right Alt release + case 0xB8: if (kb_modifier_status && 128) kb_modifier_status &= (1<<3) ^0xFF; + else kb_modifier_status &= (1<<2) ^0xFF; + break; + + // Left Ctrl or Right Ctrl make + case 0x1D: if (kb_modifier_status && 128) kb_modifier_status |= 1<<5; + else kb_modifier_status |= 1<<4; + break; + + // Left Ctrl or Right Ctrl release + case 0x9D: if (kb_modifier_status && 128) kb_modifier_status &= (1<<5) ^0xFF; + else kb_modifier_status &= (1<<5) ^0xFF; + break; + + // Caps, Num and Scroll (in this order) + case 0x3A: kb_toggle_LED (0,1,0); break; + case 0x45: kb_toggle_LED (1,0,0); break; + case 0x46: kb_toggle_LED (0,0,1); break; + + default: if (scancode & 0x80) break; + if (scancode != prev) kb_modifier_status &= (1<<7) ^0xFF; + if ((kb_modifier_status && 1) || (kb_modifier_status && 2)) + putc_pos(50, 0, kbdus_shift[scancode]); + else putc_pos (50, 0, kbdus[scancode]); + break; + } + + outportb(0x20, 0x20); +} + + +char kb_getch() +{ + regs *r = 0; + do { + prev = scancode; kb_handler(r); } + while (prev == scancode || prev+0x80 == scancode); + + + if ((kb_modifier_status && 1) || (kb_modifier_status && 2)) + return kbdus_shift[scancode]; + + return kbdus[scancode]; +} + +void kb_get_status() +{ + byte a = inportb(0x64); + puts_pos(0, 8, "KeyBrd Status: "); + put_bin(0, 9, a); +} \ No newline at end of file diff --git a/link.ld b/link.ld new file mode 100644 index 0000000..1699422 --- /dev/null +++ b/link.ld @@ -0,0 +1,25 @@ +OUTPUT_FORMAT("binary") +ENTRY(start) +phys = 0x00100000; +SECTIONS +{ + .text phys : AT(phys) { + code = .; + *(.text) + *(.rodata) + . = ALIGN(4096); + } + .data : AT(phys + (data - code)) + { + data = .; + *(.data) + . = ALIGN(4096); + } + .bss : AT(phys + (bss - code)) + { + bss = .; + *(.bss) + . = ALIGN(4096); + } + end = .; +} \ No newline at end of file diff --git a/loader.asm b/loader.asm new file mode 100644 index 0000000..c5488fc --- /dev/null +++ b/loader.asm @@ -0,0 +1,449 @@ +[BITS 32] +global start +start: mov esp, _sys_stack ; This points the stack to our new stack area + jmp stublet + + +; This part MUST be 4byte aligned, so we solve that issue using 'ALIGN 4' +ALIGN 4 +mboot: + ; Multiboot macros to make a few lines later more readable + MULTIBOOT_PAGE_ALIGN equ 1<<0 + MULTIBOOT_MEMORY_INFO equ 1<<1 + MULTIBOOT_AOUT_KLUDGE equ 1<<16 + MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 + MULTIBOOT_HEADER_FLAGS equ MULTIBOOT_PAGE_ALIGN | MULTIBOOT_MEMORY_INFO | MULTIBOOT_AOUT_KLUDGE + MULTIBOOT_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) + EXTERN code, bss, end + + ; This is the GRUB Multiboot header. A boot signature + dd MULTIBOOT_HEADER_MAGIC + dd MULTIBOOT_HEADER_FLAGS + dd MULTIBOOT_CHECKSUM + + ; AOUT kludge - must be physical addresses. Make a note of these: + ; The linker script fills in the data for these ones! + dd mboot + dd code + dd bss + dd end + dd start + +; This is an endless loop here. Make a note of this: Later on, we +; will insert an 'extern _main', followed by 'call _main', right +; before the 'jmp $'. +stublet: + extern _main + call _main + jmp $ + + +; !!! GDT !!! +; This will set up our new segment registers. We need to do +; something special in order to set CS. We do what is called a +; far jump. A jump that includes a segment as well as an offset. +; This is declared in C as 'extern void gdt_flush();' + +global _gdt_flush ; Allows the C code to link to this +extern _gp ; Says that '_gp' is in another file +_gdt_flush: + lgdt [_gp] ; Load the GDT with our '_gp' which is a special pointer + mov ax, 0x10 ; 0x10 is the offset in the GDT to our data segment + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + jmp 0x08:flush2 ; 0x08 is the offset to our code segment: Far jump! +flush2: + ret ; Returns back to the C code! + + +; !!! IDT !!! +; Loads the IDT defined in '_idtp' +global _idt_load +extern _idtp +_idt_load: + lidt [_idtp] + ret + +; !!! ISRs !!! +global _isr0 +global _isr1 +global _isr2 +global _isr3 +global _isr4 +global _isr5 +global _isr6 +global _isr7 +global _isr8 +global _isr9 +global _isr10 +global _isr11 +global _isr12 +global _isr13 +global _isr14 +global _isr15 +global _isr16 +global _isr17 +global _isr18 +global _isr19 +global _isr20 +global _isr21 +global _isr22 +global _isr23 +global _isr24 +global _isr25 +global _isr26 +global _isr27 +global _isr28 +global _isr29 +global _isr30 +global _isr31 + +_isr0: + cli + push byte 0; A normal ISR stub that pops a dummy error code to keep a + ; uniform stack frame + push byte 0 + jmp isr_common_stub +_isr1: + cli + push byte 0 + push byte 1 + jmp isr_common_stub +_isr2: + cli + push byte 0 + push byte 2 + jmp isr_common_stub +_isr3: + cli + push byte 0 + push byte 3 + jmp isr_common_stub +_isr4: + cli + push byte 0 + push byte 4 + jmp isr_common_stub +_isr5: + cli + push byte 0 + push byte 5 + jmp isr_common_stub +_isr6: + cli + push byte 0 + push byte 6 + jmp isr_common_stub +_isr7: + cli + push byte 0 + push byte 7 + jmp isr_common_stub +_isr8: + cli + push byte 8 + jmp isr_common_stub +_isr9: + cli + push byte 0 + push byte 9 + jmp isr_common_stub +_isr10: + cli + push byte 10 + jmp isr_common_stub +_isr11: + cli + push byte 11 + jmp isr_common_stub +_isr12: + cli + push byte 12 + jmp isr_common_stub +_isr13: + cli + push byte 13 + jmp isr_common_stub +_isr14: + cli + push byte 14 + jmp isr_common_stub +_isr15: + cli + push byte 0 + push byte 15 + jmp isr_common_stub +_isr16: + cli + push byte 0 + push byte 16 + jmp isr_common_stub +_isr17: + cli + push byte 0 + push byte 17 + jmp isr_common_stub +_isr18: + cli + push byte 0 + push byte 18 + jmp isr_common_stub +_isr19: + cli + push byte 0 + push byte 19 + jmp isr_common_stub +_isr20: + cli + push byte 0 + push byte 20 + jmp isr_common_stub +_isr21: + cli + push byte 0 + push byte 21 + jmp isr_common_stub +_isr22: + cli + push byte 0 + push byte 22 + jmp isr_common_stub +_isr23: + cli + push byte 0 + push byte 23 + jmp isr_common_stub +_isr24: + cli + push byte 0 + push byte 24 + jmp isr_common_stub +_isr25: + cli + push byte 0 + push byte 25 + jmp isr_common_stub +_isr26: + cli + push byte 0 + push byte 26 + jmp isr_common_stub +_isr27: + cli + push byte 0 + push byte 27 + jmp isr_common_stub +_isr28: + cli + push byte 0 + push byte 28 + jmp isr_common_stub +_isr29: + cli + push byte 0 + push byte 29 + jmp isr_common_stub +_isr30: + cli + push byte 0 + push byte 30 + jmp isr_common_stub +_isr31: + cli + push byte 0 + push byte 31 + jmp isr_common_stub + +extern _fault_handler + +isr_common_stub: + pusha + push ds + push es + push fs + push gs + mov ax, 0x10 ; Load the Kernel Data Segment descriptor! + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov eax, esp ; Push us the stack + push eax + mov eax, _fault_handler + call eax ; A special call, preserves the 'eip' register + pop eax + pop gs + pop fs + pop es + pop ds + popa + add esp, 8 ; Cleans up the pushed error code and pushed ISR number + iret ; pops 5 things at once: CS, EIP, EFLAGS, SS, and ESP! + + +; !!! IRQ !!! +global _irq0 +global _irq1 +global _irq2 +global _irq3 +global _irq4 +global _irq5 +global _irq6 +global _irq7 +global _irq8 +global _irq9 +global _irq10 +global _irq11 +global _irq12 +global _irq13 +global _irq14 +global _irq15 + +; 32: IRQ0 +_irq0: + cli + push byte 0 + push byte 32; Note that these don't push an error code on the stack: + ; We need to push a dummy error code + jmp irq_common_stub + +; 33: IRQ1 +_irq1: + cli + push byte 0 + push byte 33 + jmp irq_common_stub + +; 34: IRQ2 +_irq2: + cli + push byte 0 + push byte 34 + jmp irq_common_stub + +; 35: IRQ3 +_irq3: + cli + push byte 0 + push byte 35 + jmp irq_common_stub + +; 36: IRQ4 +_irq4: + cli + push byte 0 + push byte 36 + jmp irq_common_stub + +; 37: IRQ5 +_irq5: + cli + push byte 0 + push byte 37 + jmp irq_common_stub + +; 38: IRQ6 +_irq6: + cli + push byte 0 + push byte 38 + jmp irq_common_stub + +; 39: IRQ7 +_irq7: + cli + push byte 0 + push byte 39 + jmp irq_common_stub + +; 40: IRQ8 +_irq8: + cli + push byte 0 + push byte 40 + jmp irq_common_stub +; 41: IRQ9 +_irq9: + cli + push byte 0 + push byte 41 + jmp irq_common_stub + +; 42: IRQ10 +_irq10: + cli + push byte 0 + push byte 42 + jmp irq_common_stub + +; 43: IRQ11 +_irq11: + cli + push byte 0 + push byte 43 + jmp irq_common_stub + +; 44: IRQ12 +_irq12: + cli + push byte 0 + push byte 44 + jmp irq_common_stub + +; 45: IRQ13 +_irq13: + cli + push byte 0 + push byte 45 + jmp irq_common_stub + +; 46: IRQ14 +_irq14: + cli + push byte 0 + push byte 46 + jmp irq_common_stub + +; 47: IRQ15 +_irq15: + cli + push byte 0 + push byte 47 + jmp irq_common_stub + +extern _irq_handler + +; This is a stub that we have created for IRQ based ISRs. This calls +; '_irq_handler' in our C code. We need to create this in an 'irq.c' +irq_common_stub: + pusha + push ds + push es + push fs + push gs + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov eax, esp + push eax + mov eax, _irq_handler + call eax + pop eax + pop gs + pop fs + pop es + pop ds + popa + add esp, 8 + iret + + + +SECTION .bss + resb 8192 ; This reserves 8KBytes of memory here +_sys_stack: \ No newline at end of file diff --git a/loader.o b/loader.o new file mode 100644 index 0000000..2730558 Binary files /dev/null and b/loader.o differ diff --git a/main.c b/main.c new file mode 100644 index 0000000..84c99d2 --- /dev/null +++ b/main.c @@ -0,0 +1,65 @@ +#include +#include +#include "gdt.c" +#include "idt.c" +#include "isrs.c" +#include "irq.c" +#include "timer.c" +#include "keyus.c" +#include "init.c" + + +/*void put_line_scroll(int line, char c) +{ + int i = 0; + while (TextVideoRam[2*(80*line+i)] != 0 && i<=80) ++i; + if (i>78) { + memcpy(TextVideoRam + (2*80*line), TextVideoRam + (2*80*line) + 2, (i+1)*2); + } + putc_pos(i, line, c); +}*/ + + +int main() +{ + system_init(); + set_default_colors (0x07, 0x04); + clrscr(); + + int i; + for (i=0;i<80;i++) putc_pos_font (i, 0, ' ', 0x02, 0x0F); + puts_pos_font (60, 0, "Uptime:", 0x02, 0x0E); cursor_y++; + + // Do other stuff + puts ("Testing puts...\nAnd this shoudl be new line\n"); + puts_font ("And this should be colored in another color ", 0x02, 0x0F); + puts ("<- colored font should be right about heree"); + + puts_pos (0, 23, "This text should be starting in position (0, 23)"); + puts_pos_font (0, 23, "THIS", 0x00, 0x09); + + puts_pos (5, 20, "<- The cursor should be blinking right here"); + putc_pos_font (3, 20, 0, 0x04, 0x0F); + text_mode_cursor(3, 20); + + + while (1) { + kb_get_status(); + + put_bin(60, 15, kb_modifier_status); + puts_pos_font (60, 16, "LShift", 0x07, 0x08 - (kb_modifier_status&1)*0x06); + puts_pos_font (60, 17, "RShift", 0x07, 0x08 - (kb_modifier_status&2)*0x06); + puts_pos_font (60, 18, "LAlt", 0x07, 0x08 - (kb_modifier_status&4)*0x06); + puts_pos_font (60, 19, "RAlt", 0x07, 0x08 - (kb_modifier_status&8)*0x06); + puts_pos_font (60, 20, "LCtrl", 0x07, 0x08 - (kb_modifier_status&16)*0x06); + puts_pos_font (60, 21, "RCtrl", 0x07, 0x08 - (kb_modifier_status&32)*0x06); + puts_pos_font (60, 22, "FakeShift", 0x07, 0x08 - (kb_modifier_status&64)*0x06); + puts_pos_font (60, 23, "Special", 0x07, 0x08 - (kb_modifier_status&128)*0x06); + + putc (kb_getch()); + } + + // do nothing + for(;;); + return 0; +} \ No newline at end of file diff --git a/main.o b/main.o new file mode 100644 index 0000000..5f8a70a Binary files /dev/null and b/main.o differ diff --git a/timer.c b/timer.c new file mode 100644 index 0000000..3e09c41 --- /dev/null +++ b/timer.c @@ -0,0 +1,52 @@ +#include +int timer_ticks = 0; +int timer_hz; + +void timer_phase(int hz) +{ + int divisor = 1193180/hz; // Calculate the divisor + outportb(0x43, 0x36); // Set our command byte 0x36 + outportb(0x40, divisor&0xFF); // Set low byte + outportb(0x40, divisor>>8); // Set high byte + timer_hz = hz; +} + +void timer_clock (int x, int y, int secs) +{ + int s, m, h; + char arr[9] = {0,0,0,0,0,0,0,0,0}; + + s = secs%60; + m = (secs/60)%60; + h = secs/3600; + + arr[0] = (h/10)%10 + '0'; if (arr[0]=='0') arr[0] = ' '; + arr[1] = h%10 + '0'; + + arr[3] = (m/10) + '0'; + arr[4] = m%10 + '0'; + + arr[6] = s/10 + '0'; + arr[7] = s%10 + '0'; + + if (secs%2 == 0) { + arr[2] = ' '; + arr[5] = ' '; + } + else { + arr[2] = ':'; + arr[5] = ':'; + } + + puts_pos(x, y, arr); +} + + +void timer_handler(regs *r) +{ + timer_ticks++; + + if (timer_ticks % timer_hz) { + timer_clock (70, 0, timer_ticks / timer_hz); + } +} \ No newline at end of file