This commit is contained in:
Tiberiu Chibici 2021-09-14 18:29:04 +03:00
parent 7cafad0682
commit c90c6dc692
18 changed files with 1537 additions and 1 deletions

2
.gitignore vendored
View File

@ -5,7 +5,7 @@
# Compiled Object files
*.slo
*.lo
*.o
#*.o
*.obj
# Precompiled Headers

22
compile.bat Normal file
View File

@ -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

BIN
console.o Normal file

Binary file not shown.

78
gdt.c Normal file
View File

@ -0,0 +1,78 @@
#include <system.h>
/* 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();
}

62
idt.c Normal file
View File

@ -0,0 +1,62 @@
#include <system.h>
/* 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();
}

152
include/console.h Normal file
View File

@ -0,0 +1,152 @@
#include <system.h>
#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

104
include/system.h Normal file
View File

@ -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

37
init.c Normal file
View File

@ -0,0 +1,37 @@
#include <system.h>
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();
}

118
irq.c Normal file
View File

@ -0,0 +1,118 @@
#include <system.h>
/* 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);
}

163
isrs.c Normal file
View File

@ -0,0 +1,163 @@
#include <system.h>
#include <console.h>
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 (;;);
}
}

BIN
kernel.bin Normal file

Binary file not shown.

209
keyus.c Normal file
View File

@ -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);
}

25
link.ld Normal file
View File

@ -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 = .;
}

449
loader.asm Normal file
View File

@ -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:

BIN
loader.o Normal file

Binary file not shown.

65
main.c Normal file
View File

@ -0,0 +1,65 @@
#include <system.h>
#include <console.h>
#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;
}

BIN
main.o Normal file

Binary file not shown.

52
timer.c Normal file
View File

@ -0,0 +1,52 @@
#include<system.h>
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);
}
}