This commit is contained in:
2021-09-14 18:30:00 +03:00
parent c90c6dc692
commit 7cb940e485
48 changed files with 2621 additions and 507 deletions

25
kernel/clock/cmos.h Normal file
View File

@ -0,0 +1,25 @@
volatile static byte cmos_data[128];
void cmos_write ()
{
byte i;
for (i = 0; i < 128; i++) {
//asm volatile ("cli");
outportb(0x70, i);
iowait();
outportb(0x71, cmos_data[i]);
//asm volatile ("sti");
}
}
void cmos_read ()
{
byte i;
for (i = 0; i < 128; i++) {
//asm volatile ("cli");
outportb(0x70, i);
iowait();
cmos_data[i] = inportb(0x71);
//asm volatile ("sti");
}
}

76
kernel/clock/pictimer.c Normal file
View File

@ -0,0 +1,76 @@
#include <system.h>
#include "time.c"
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 clock_show (int uptime_secs)
{
int i;
for (i=0;i<80;i++) putc_pos_font (i, 0, ' ', 0x02, 0x0F);
puts_pos_font (64, 0, "Uptime:", 0x02, 0x0E);
unsigned int uptime;
uptime = uptime_secs%60; // Seconds
uptime += 100* ((uptime_secs/60)%60); // Minutes
uptime += 10000*(uptime_secs/3600); // Hours
for (i=79;i>71;i--) {
if (i==77 || i==74) {
if (uptime_secs%2==0) putc_pos_font(i, 0, ':', 0x02, 0x0F);
else putc_pos_font(i, 0, ' ', 0x02, 0x0F);
}
else {
putc_pos_font(i, 0, (uptime%10)+'0', 0x02, 0x0F);
uptime/=10;
}
}
// PRINT CURRENT TIME
uptime = clock.seconds; // Seconds
uptime += 100* clock.minutes; // Minutes
uptime += 10000*clock.hours; // Hours
for (i=9;i>1;i--) {
if (i==7 || i==4) {
if (uptime_secs%2==0) putc_pos_font(i, 0, ':', 0x02, 0x0F);
else putc_pos_font(i, 0, ' ', 0x02, 0x0F);
}
else {
putc_pos_font(i,0, (uptime%10)+'0', 0x02, 0x0F);
uptime/=10;
}
}
if (clock.am_pm==0) puts_pos_font(10, 0, "am", 0x02, 0x0F);
else puts_pos_font(10, 0, "pm", 0x02, 0x0F);
// PRINT DATE
putc_pos_font(32, 0, (clock.day/10)+'0', 0x02, 0x0E);
putc_pos_font(33, 0, (clock.day%10)+'0', 0x02, 0x0E);
puts_pos_font(35, 0, (char*)clock_months[clock.month], 0x02, 0x0F);
putc_pos_font(35+strlen(clock_months[clock.month])+1, 0, (clock.century/10)+'0', 0x02, 0x0E);
putc_pos_font(35+strlen(clock_months[clock.month])+2, 0, (clock.century%10)+'0', 0x02, 0x0E);
putc_pos_font(35+strlen(clock_months[clock.month])+3, 0, (clock.year/10)+'0', 0x02, 0x0E);
putc_pos_font(35+strlen(clock_months[clock.month])+4, 0, (clock.year%10)+'0', 0x02, 0x0E);
}
void timer_handler(regs *r)
{
timer_ticks++;
if (timer_ticks % timer_hz == 0) {
clock_show (timer_ticks / timer_hz);
clock_inc();
}
}

143
kernel/clock/time.c Normal file
View File

@ -0,0 +1,143 @@
#ifndef __TIME_C
#define __TIME_C
#include "cmos.h"
static const char* clock_months[] = {0,
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"};
static const char* clock_weekdays[] = {0,
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
byte clock_months_len[] = {
0,
31, // January
28, // February
31, // March
30, // April
31, // May
30, // June
31, // July
31, // August
30, // September
31, // October
30, // November
31 // December
};
typedef struct {
byte seconds;
byte minutes;
byte hours;
byte weekday;
byte day;
byte month;
byte year;
byte century;
byte am_pm;
} TIME;
volatile static TIME clock;
void RTC_get_time()
{
cmos_read();
if ((cmos_data[0x0b]&4)==0) // BCD = true;
{
clock.seconds = (cmos_data[0x00]%16) + 10*(cmos_data[0x00]/16);
clock.minutes = (cmos_data[0x02]%16) + 10*(cmos_data[0x02]/16);
if ((cmos_data[0x0b]&2)==0) { // AM/PM
if (cmos_data[0x04]&80) { // pm
clock.hours = ((cmos_data[0x04]-0x80)%16) + 10*((cmos_data[0x04]-0x80)/16);
clock.am_pm = 1;
}
else { // am
clock.hours = (cmos_data[0x04]%16) + 10*(cmos_data[0x04]/16);
clock.am_pm = 0;
}
}
else { // 24 hours
clock.hours = (cmos_data[0x04]%16) + 10*(cmos_data[0x04]/16);
if (clock.hours > 12) {
clock.am_pm = 1;
clock.hours -= 12;
}
else clock.am_pm = 0;
}
clock.weekday = (cmos_data[0x06]%16) + 10*(cmos_data[0x06]/16);
clock.day = (cmos_data[0x07]%16) + 10*(cmos_data[0x07]/16);
clock.month = (cmos_data[0x08]%16) + 10*(cmos_data[0x08]/16);
clock.year = (cmos_data[0x09]%16) + 10*(cmos_data[0x09]/16);
clock.century = (cmos_data[0x32]%16) + 10*(cmos_data[0x32]/16);
}
else {//BCD = false;
clock.seconds = cmos_data[0x00];
clock.minutes = cmos_data[0x02];
if ((cmos_data[0x0b]&2)==0) { // AM/PM
if (cmos_data[0x04]&80) { // pm
clock.hours = cmos_data[0x04]-0x80;
clock.am_pm = 1;
}
else { // am
clock.hours = cmos_data[0x04];
clock.am_pm = 0;
}
}
else { // 24 hours
clock.hours = cmos_data[0x02];
if (clock.hours > 12) {
clock.am_pm = 1;
clock.hours -= 12;
}
else clock.am_pm = 0;
}
clock.weekday = cmos_data[0x06];
clock.day = cmos_data[0x07];
clock.month = cmos_data[0x08];
clock.year = cmos_data[0x09];
clock.century = cmos_data[0x32];
}
// Leap years
if (clock.year % 4 == 0) clock_months_len[2]=29;
}
void clock_inc()
{
// New minute
if (++clock.seconds > 59) {
clock.seconds = 0;
// New hour
if (++clock.minutes > 59) {
clock.minutes = 0;
clock.hours++;
if (clock.hours == 12 && clock.am_pm == 1) { // 11:59pm -> 0:00am
clock.hours = 0; clock.am_pm = 0;
// New day
clock.weekday = 1+(clock.weekday%7);
// New month
if (++clock.day > clock_months_len[clock.month]) {
clock.day = 1;
// New year
if (++clock.month>12) {
clock.month = 1;
// New century
if (++clock.year > 99) {
clock.year = 0;
clock.century++;
}
}
}
}
else if (clock.hours == 12 && clock.am_pm == 0) // 11:59am -> 12:00pm
clock.am_pm = 1;
else if (clock.hours == 13 && clock.am_pm == 1) // 12:59pm -> 1:59pm
clock.hours = 1;
}
}
}
#endif

23
kernel/compile.bat Normal file
View File

@ -0,0 +1,23 @@
@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 KERNEL.BIN C:\SHARE
copy KERNEL.BIN A:\KERNEL.CTA

BIN
kernel/console.o Normal file

Binary file not shown.

172
kernel/include/conio.h Normal file
View File

@ -0,0 +1,172 @@
#include <system.h>
#ifndef __CONIO_H
#define __CONIO_H
#define _ATTRIB 0x0F
byte default_background, default_foreground;
char hex[] = "0123456789ABCDEF";
// 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 prev_line()
{
cursor_x = 79;
if (--cursor_y < 0) {
cursor_y = 0; cursor_x=0;
}
}
void next_line()
{
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) next_line();
if (c == '\n') {next_line(); 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) next_line();
if (c == '\n') {next_line(); 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(unsigned int alpha)
{
char nr[9];
int i;
for (i = 7; i >= 0; i--) {
nr[i] = hex[alpha%16];
alpha /= 16;
}
nr[8] = 0;
puts(nr);
}
void put_hex_pos(int x, int y, unsigned int alpha)
{
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

View File

@ -0,0 +1,40 @@
// 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;
// Functions
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) ;
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();
void kb_handler(regs *r);
void reboot();
void kb_waitin();

85
kernel/include/system.h Normal file
View File

@ -0,0 +1,85 @@
#ifndef __SYSTEM_H
#define __SYSTEM_H
#include <sys/declarat.h>
#define true 1
#define false 0
byte *TextVideoRam;
volatile static int cursor_x, cursor_y;
int current_mode_width;
int current_mode_height;
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!=0; str++) i++;
return i;
}
int strcmp(const char *pStr1, const char *pStr2)
{
char c1, c2;
int v;
do {
c1 = *pStr1++;
c2 = *pStr2++;
/* the casts are necessary when pStr1 is shorter & char is signed */
v = (unsigned int)c1 - (unsigned int)c2;
} while ((v == 0) && (c1 != '\0'));
return v;
}
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;
}
static inline void iowait() {
asm volatile ("outb %al, $0x80");
}
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

BIN
kernel/kernel.bin Normal file

Binary file not shown.

8
kernel/kernel/epilogue.c Normal file
View File

@ -0,0 +1,8 @@
void reboot()
{
unsigned char good = 0x02;
while ((good & 0x02) != 0)
good = inportb(0x64);
outportb(0x64, 0xFE);
__asm__ __volatile__ ("hlt");
}

78
kernel/kernel/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
kernel/kernel/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();
}

125
kernel/kernel/irq.c Normal file
View File

@ -0,0 +1,125 @@
#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(int pic1, int pic2)
{
// Send ICW1
outportb(0x20, 0x11);
outportb(0xA0, 0x11);
// send ICW2
outportb(0x21, pic1); // remap pics
outportb(0xA1, pic2);
// send ICW3
outportb(0x21, 4);
outportb(0xA1, 2);
// Send ICW4
outportb(0x21, 0x01);
outportb(0xA1, 0x01);
outportb(0x21, 0x00);
}
/* 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(32,40);
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);
}

162
kernel/kernel/isrs.c Normal file
View File

@ -0,0 +1,162 @@
#include <system.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_pos(15, 4, r->gs);
puts_pos_font (10, 5, "fs", 0x01, 0x0B); put_hex_pos(15, 5, r->fs);
puts_pos_font (10, 6, "es", 0x01, 0x0B); put_hex_pos(15, 6, r->es);
puts_pos_font (10, 7, "ds", 0x01, 0x0B); put_hex_pos(15, 7, r->ds);
puts_pos_font (40, 4, "edi", 0x01, 0x0B); put_hex_pos(45, 4, r->edi);
puts_pos_font (40, 5, "esi", 0x01, 0x0B); put_hex_pos(45, 5, r->esi);
puts_pos_font (40, 6, "ebp", 0x01, 0x0B); put_hex_pos(45, 6, r->ebp);
puts_pos_font (40, 7, "esp", 0x01, 0x0B); put_hex_pos(45, 7, r->esp);
puts_pos_font (10, 9, "eax", 0x01, 0x0B); put_hex_pos(15, 9, r->eax);
puts_pos_font (10, 10, "ebx", 0x01, 0x0B); put_hex_pos(15, 10, r->ebx);
puts_pos_font (40, 9, "ecx", 0x01, 0x0B); put_hex_pos(45, 9, r->ecx);
puts_pos_font (40, 10, "edx", 0x01, 0x0B); put_hex_pos(45, 10, r->edx);
puts_pos_font (10, 12, "int_no", 0x01, 0x0B); put_hex_pos(17, 12, r->int_no);
puts_pos_font (10, 14, "Error code:", 0x01, 0x0B); put_hex_pos(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_pos(17, 17, r->eip);
puts_pos_font (10, 18, "cs", 0x01, 0x0B); put_hex_pos(17, 18, r->cs);
puts_pos_font (10, 19, "eflags", 0x01, 0x0B); put_hex_pos(17, 19, r->eflags);
puts_pos_font (10, 20, "useresp", 0x01, 0x0B); put_hex_pos(17, 20, r->useresp);
puts_pos_font (10, 21, "ss", 0x01, 0x0B); put_hex_pos(17, 21, r->ss);
puts_pos_font (29, 24, "!!! System Halted !!!", 0x01, 0x0C);
for (;;);
}
}

4
kernel/kernel/memory.c Normal file
View File

@ -0,0 +1,4 @@
extern unsigned long* read_cr0();
extern unsigned long* read_cr3();
extern void write_cr0(unsigned long* alpha);
extern void write_cr3(unsigned long* alpha);

61
kernel/kernel/prologue.c Normal file
View File

@ -0,0 +1,61 @@
#include <system.h>
#include "gdt.c"
#include "idt.c"
#include "isrs.c"
#include "irq.c"
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();
RTC_get_time();
__asm__ __volatile__ ("sti");
// Install PIT timer
timer_ticks = 0;
timer_phase (100);
irq_install_handler(0, timer_handler);
// Install keyboard (part 1): install IRQ1 and start BAT test
kb_modifier_status = 0;
irq_install_handler(1, kb_handler);
kb_waitin(); outportb(0x60, 0xFF); // Reset kb
// other drivers come here!!;
// Install keyboard (part 2): BAT test results & set repeat rates
byte temp;
do temp = inportb(0x60);
while (temp!=0xAA && temp!=0xFC);
// KB failed BAT TEST
if (temp == 0xFC) puts_font("\nKeyboard error: failed BAT test.", 0x07, 0x0C);
kb_set_repeat(1, 11);
// Install keyboard (part 3): set scancode set 2
kb_set_scancodeset(2); // Set new scancode set
kb_waitin(); outportb(0x64, 0x20); // Get "Command byte"
do { temp = inportb(0x60);
} while (temp==0xFA || temp==0xAA);
temp &= 0xFF - (1<<6); // Set bit6 to 0: disable conversion
kb_waitin(); outportb(0x64, 0x60); // Function to write cmd byte
kb_waitin(); outportb(0x60, temp); // Send it
memset(kb_array, 0, 16);
}

View File

@ -0,0 +1,135 @@
*0x00 Pause/Break
0x01 F9
0x02 F7
0x03 F5
0x04 F3
0x05 F1
0x06 F2
0x07 F12
0x08 Print Screen
0x09 F10
0x0A F8
0x0B F6
0x0C F4
0x0D Tab
0x0E `~
0x0F
0x10
0x11
0x12
0x13
0x14
0x15 Q
0x16 1!
0x17
0x18
0x19
0x1A Z
0x1B S
0x1C A
0x1D W
0x1E 2@
0x1F LeftWin
0x20
0x21 C
0x22 X
0x23 D
0x24 E
0x25 4$
0x26 3#
0x27 RightWin
0x28
0x29 Space
0x2A V
0x2B F
0x2C T
0x2D R
0x2E 5%
0x2F Menu
0x30
0x31 N
0x32 B
0x33 H
0x34 G
0x35 Y
0x36 6^
0x37
0x38
0x39
0x3A M
0x3B J
0x3C U
0x3D 7&
0x3E 8*
0x3F
0x40
0x41 ,<
0x42 K
0x43 I
0x44 O
0x45 0)
0x46 9(
0x47
0x48
0x49 .>
0x4A /?
0x4B L
0x4C ;:
0x4D P
0x4E -_
0x4F
0x50
0x51
0x52 '"
0x53
0x54 [{
0x55 =+
0x56
0x57
0x58
0x59 Numpad Enter
0x5A Enter
0x5B ]}
0x5C
0x5D \|
0x5E End
0x5F Left
0x60 Home
0x61 Insert
0x62 Delete
0x63 Down
0x64 Right
0x65 Up
0x66 Backspace
0x67 PageDown
0x68 PageUp
0x69 Numpad 1 (end)
0x6A Numpad /
0x6B Numpad 4 (left)
0x6C Numpad 7 (Home)
0x6D
0x6E
0x6F
0x70 Numpad 0 (insert)
0x71 Numpad . (del)
0x72 Numpad 2 (down)
0x73 Numpad 5
0x74 Numpad 6 (right)
0x75 Numpad 8 (up)
0x76 Esc
0x77
0x78 F11
0x79 Numpad +
0x7A Numpad 3 (pgdwn)
0x7B Numpad -
0x7C Numpad *
0x7D Numpad 9 (pgup)
0x7E
0x7F

60
kernel/keyboard/keyb.c Normal file
View File

@ -0,0 +1,60 @@
void kb_test()
{
byte temp=0, secs=0;
puts("\nTHIS WILL TEST FEW COMMANDS OF THE PS/2 KEYBOARD.\n");
puts("\nEcho... ");
while ((inportb(0x64)&2)!=0);
outportb(0x60, 0xEE);
/* while ((inportb(0x64)&1)!=0);
temp = inportb(0x60);
putc_font('[', 0x07, 0x02);
putc_font(hex[temp/16], 0x07, 0x02);
putc_font(hex[temp%16], 0x07, 0x02);
putc_font(']', 0x07, 0x02);*/
puts("\nSet LEDs - SCROLL on... ");
while ((inportb(0x64)&2)!=0);
outportb(0x60, 0xED);
/* while ((inportb(0x64)&2)!=0);
outportb(0x60, 1);
while ((inportb(0x64)&1)!=0);
temp = inportb(0x60);*/
putc_font('[', 0x07, 0x02);
putc_font(hex[temp/16], 0x07, 0x02);
putc_font(hex[temp%16], 0x07, 0x02);
putc_font(']', 0x07, 0x02);
puts("\nGet current scancode set... ");
while ((inportb(0x64)&2)!=0);
outportb(0x60, 0xF0);
while ((inportb(0x64)&2)!=0);
outportb(0x60, 0);
/* while ((inportb(0x64)&1)!=0);
temp = inportb(0x60);
putc_font('[', 0x07, 0x02);
putc_font(hex[temp/16], 0x07, 0x02);
putc_font(hex[temp%16], 0x07, 0x02);
putc_font(']', 0x07, 0x02);*/
puts("\nTurning on 2 leds (don't know which ones :P)... ");
while ((inportb(0x64)&2)!=0);
outportb(0x60, 0xED);
while ((inportb(0x64)&2)!=0);
outportb(0x60, (byte)1|2);
/* while ((inportb(0x64)&1)!=0);
temp = inportb(0x60);
putc_font('[', 0x07, 0x02);
putc_font(hex[temp/16], 0x07, 0x02);
putc_font(hex[temp%16], 0x07, 0x02);
putc_font(']', 0x07, 0x02);*/
}

179
kernel/keyboard/keyus.c Normal file
View File

@ -0,0 +1,179 @@
#include "keyus.h"
// kb_key_return 4-byte structure
typedef struct {
byte status;
byte lights;
byte scancode;
byte character;
} kb_key;
byte kb_array[16];
volatile static byte kb_newdata;
/*********DEBUG**************/
void kb_print_binary(int x, int y, byte what)
{
char arr[9]; int i;
for (i = 7; i>=0; i--, what/=2)
arr[i] = (what%2) + '0';
arr[8] = 0;
puts_pos(x,y,arr);
}
/*********DEBUG**************/
void kb_set_key(byte scancode, byte val)
{
byte pos = scancode/8;
byte offset = scancode%8;
if (val) {
kb_array[pos] |= 1<<offset;
kb_newdata = scancode;
}
else kb_array[pos] &= 0xFF - (1<<offset);
}
byte kb_get_key(byte scancode)
{
byte pos = scancode/8;
byte offset = scancode%8;
return (kb_array[pos]&(1<<offset));
}
void kb_handler(regs *r) {
byte scancode = inportb(0x60);
switch (scancode) {
case 0x00: // Error 0x00
case 0xFC: // Diagnostics failed (MF kb)
case 0xFD: // Diagnostics failed (AT kb)
case 0xFF: kb_waitin(); outportb(0x60, 0xF4); // Error 0xFF
break;
case 0xAA: // BAT test successful.
case 0xFA: // ACKnowledge
case 0xFE: // Last command invalid or parity error
case 0xEE: break; // Echo response
// Gray or break
case 0xE0: kb_prefix |= 1; break;
case 0xE1: kb_prefix |= 4; break;
case 0xF0: kb_prefix |= 2; break;
// Alt, ctrl...
case 0x11: if ((kb_prefix&1) == 0) { // Left alt
if ((kb_prefix&2) == 0) kb_modifier_status |= 1<<2;
else kb_modifier_status &= 0xFF - (1<<2);
}
else { // Right alt
if ((kb_prefix&2) == 0) kb_modifier_status |= 1<<3;
else kb_modifier_status &= 0xFF - (1<<3);
}
kb_prefix = 0; break;
case 0x12: if ((kb_prefix&1) == 0) { // Left shift
if ((kb_prefix&2) == 0) kb_modifier_status |= 1<<0;
else kb_modifier_status &= 0xFF - (1<<0);
}
else { // Fake shift
if ((kb_prefix&2) == 0) kb_modifier_status |= 1<<6;
else kb_modifier_status &= 0xFF - (1<<6);
}
kb_prefix = 0; break;
//TO ADD BELOW: pause/break byte1
case 0x14: if (kb_prefix&4) {
if ((kb_prefix&2) == 0) kb_set_key (0, 1);
else kb_set_key (0, 0);
kb_prefix |= 8; break;
}
else if ((kb_prefix&1) == 0) { // Left ctrl
if ((kb_prefix&2) == 0) kb_modifier_status |= 1<<4;
else kb_modifier_status &= 0xFF - (1<<4);
}
else { // Right ctrl
if ((kb_prefix&2) == 0) kb_modifier_status |= 1<<5;
else kb_modifier_status &= 0xFF - (1<<5);
}
kb_prefix = 0; break;
case 0x59: // Right shift
if ((kb_prefix&2) == 0) kb_modifier_status |= 1<<1;
else kb_modifier_status &= 0xFF - (1<<1);
kb_prefix = 0; break;
// LEDs
case 0x58: if ((kb_prefix&2) == 0) {
kb_lights_status ^= 4; kb_set_LEDs(kb_lights_status);
} kb_prefix = 0; break; // Caps
//TO ADD BELOW: pause/break byte2
case 0x77:
if ((kb_prefix&4) && (kb_prefix&8)) kb_prefix=0;
else if ((kb_prefix&2) == 0) {
kb_lights_status ^= 2; kb_set_LEDs(kb_lights_status);
} kb_prefix = 0; break; // Num
case 0x7E: if ((kb_prefix&2) == 0) {
kb_lights_status ^= 1; kb_set_LEDs(kb_lights_status);
} kb_prefix = 0; break; // Scroll
case 0x83: scancode = 0x02; // Put F7 under the 0x80 (128bit) barrier
default:
// Remap gray keys
if (kb_prefix&1) switch (scancode) {
case 0x7C: scancode=0x08; break; // PrintScreen
case 0x4A: scancode=0x6A; break; // Numpad /
case 0x5A: scancode=0x59; break; // Numpad Enter
case 0x69: scancode=0x5E; break; // End
case 0x6B: scancode=0x5F; break; // Left
case 0x6C: scancode=0x60; break; // Home
case 0x70: scancode=0x61; break; // Insert
case 0x71: scancode=0x62; break; // Delete
case 0x72: scancode=0x63; break; // Down
case 0x74: scancode=0x64; break; // Right
case 0x75: scancode=0x65; break; // Up
case 0x7A: scancode=0x67; break; // PageDown
case 0x7D: scancode=0x68; break; // PageUp
}
if ((kb_prefix&2) == 0) kb_set_key(scancode, 1);
else kb_set_key(scancode, 0);
kb_prefix = 0; break;
}
// Alt+ctrl+del = reset
if (scancode==0x62) {
int ok=0;
if ((kb_modifier_status&4) || (kb_modifier_status&8)) ok++;
if ((kb_modifier_status&16) || (kb_modifier_status&32)) ok++;
if (ok==2) reboot();
}
outportb(0x20, 0x20);
}
kb_key kb_getkey()
{
kb_key ret;
kb_newdata = 0xFF;
while (kb_newdata==0xFF); // wait for keypress
ret.scancode = kb_newdata; // Send scancode for non-chars
ret.status = kb_modifier_status; // Shift, ctrl... state
ret.lights = kb_lights_status; // Num, caps.... state
if ((ret.status & 1) || (ret.status & 2)) // Shift is on
ret.character = kbdus_map_shift[ret.scancode];
else ret.character = kbdus_map[ret.scancode]; // Shift is off
return ret; // And send it.
}

137
kernel/keyboard/keyus.h Normal file
View File

@ -0,0 +1,137 @@
void kb_set_LEDs(byte status);
void kb_set_repeat(byte rate, byte delay);
void kb_set_scancodeset(byte set);
char kbdus_map[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t', '`', 0,
0, 0, 0, 0, 0, 'q', '1', 0, 0, 0, 'z', 's', 'a', 'w', '2', 0,
0, 'c', 'x', 'd', 'e', '4', '3', 0, 0, ' ', 'v', 'f', 't', 'r', '5', 0,
0, 'n', 'b', 'h', 'g', 'y', '6', 0, 0, 0, 'm', 'j', 'u', '7', '8', 0,
0, ',', 'k', 'i', 'o', '0', '9', 0, 0, '.', '/', 'l', ';', 'p', '-', 0,
0, 0, '\'', 0, '[', '=', 0, 0, 0, '\n', '\n', ']', 0, '\\', 0, 0,
0, 0, 0x7F, 0, 0, 0, '\b', 0, 0, '1', '/', '4', '7', 0, 0, 0,
'0', '.', '2', '5', '6', '8', 0, 0, 0, '+', '3', '-', '*', '9', 0, 0
};
char kbdus_map_shift[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t', '~', 0,
0, 0, 0, 0, 0, 'Q', '!', 0, 0, 0, 'Z', 'S', 'A', 'W', '@', 0,
0, 'C', 'X', 'D', 'E', '$', '#', 0, 0, ' ', 'V', 'F', 'T', 'R', '%', 0,
0, 'N', 'B', 'H', 'G', 'Y', '^', 0, 0, 0, 'M', 'J', 'U', '&', '*', 0,
0, '<', 'K', 'I', 'O', ')', '(', 0, 0, '>', '?', 'L', ':', 'P', '_', 0,
0, 0, '\"', 0, '{', '+', 0, 0, 0, '\n', '\n', '}', 0, '|', 0, 0,
0, 0, 0x7F, 0, 0, 0, '\b', 0, 0, '1', '/', '4', '7', 0, 0, 0,
'0', '.', '2', '5', '6', '8', 0, 0, 0, '+', '3', '-', '*', '9', 0, 0
};
/* 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 */
byte kb_modifier_status;
/* kb_modifier_status:
BIT | Description
----+-----------------------------------
0 | Gray
1 | Break code
2 | 0xE1 (pause/break)
3 | Recieved first byte from pause/break */
byte kb_prefix;
/* kb_lights_status
BIT | Description
----+-----------------------------------
0 | SCROLLOCK
1 | NUMLOCK
2 | CAPSLOCK */
byte kb_lights_status;
byte kb_scancode_set;
/***************************************
* Set repeat rate/delay *
***************************************
Values for inter-character delay (bits 4-0)
(characters per second; default is 10.9)
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7
----+----+----+----+----+----+----+----+----
0 |30.0|26.7|24.0|21.8|20.0|18.5|17.1|16.0
8 |15.0|13.3|12.0|10.9|10.0|9.2 |8.6 |8.0
16 |7.5 |6.7 |6.0 |5.5 |5.0 |4.6 |4.3 |4.0
24 |3.7 |3.3 |3.0 |2.7 |2.5 |2.3 |2.1 |2.0
Values for delay:
(miliseconds; default is 500)
0 | 1 | 2 | 3
-----+-----+-----+-----
250 | 500 | 750 | 1000
***************************************/
void kb_set_repeat(byte rate, byte delay)
{
if (rate>3 || delay>31) return;
byte out = rate<<5 | delay;
while ((inportb(0x64)&2) != 0);
outportb(0x60, 0xF3);
while ((inportb(0x64)&2) != 0);
outportb(0x60, out);
}
/***************************************
* Set keyboard LEDs *
***************************************
+-----------+-------+-------+--------+
| Bits 7-3 | Bit 2 | Bit 1 | Bit 0 |
| 0 | Caps | Num | Scroll |
|(reserved) | lock | lock | lock |
+-----------+-------+-------+--------+
***************************************/
void kb_set_LEDs(byte status)
{
while ((inportb (0x64)&2)!=0);
outportb (0x60, 0xED);
while ((inportb (0x64)&2)!=0);
outportb (0x60, status);
}
/***************************************
* Set scancode set *
***************************************
0 Get current scancode set
1 Set to scancode set 1
2 Set to scancode set 2
3 Set to scancode set 3
***************************************/
void kb_set_scancodeset(byte set)
{
//If ask for current scancode, tell kb handler what to expect
if (set==0) kb_scancode_set = 4;
while ((inportb (0x64)&2)!=0);
outportb (0x60, 0xF0);
while ((inportb (0x64)&2)!=0);
outportb (0x60, set);
}
void kb_waitin()
{
int fail_safe=200000;
while ((inportb(0x64)&2)!=0 && fail_safe>0) fail_safe--;
}
void kb_waitout()
{
int fail_safe=200000;
while ((inportb(0x64)&1)==0 && fail_safe>0) fail_safe--;
}

25
kernel/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 = .;
}

478
kernel/loader.asm Normal file
View File

@ -0,0 +1,478 @@
[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
[global _read_cr0]
_read_cr0:
mov eax, cr0
retn
[global _write_cr0]
_write_cr0:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov cr0, eax
pop ebp
retn
[global _read_cr3]
_read_cr3:
mov eax, cr3
retn
[global _write_cr3]
_write_cr3:
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov cr3, eax
pop ebp
retn
SECTION .bss
resb 8192 ; This reserves 8KBytes of memory here
_sys_stack:

BIN
kernel/loader.o Normal file

Binary file not shown.

18
kernel/main.c Normal file
View File

@ -0,0 +1,18 @@
#include <system.h>
#include <conio.h>
#include "clock/pictimer.c"
#include "keyboard/keyus.c"
#include "kernel/prologue.c"
#include "kernel/epilogue.c"
#include "shell/shell.c"
int main()
{
system_init();
shell();
// do nothing
for(;;);
return 0;
}

BIN
kernel/main.o Normal file

Binary file not shown.

122
kernel/shell/apps.h Normal file
View File

@ -0,0 +1,122 @@
const char *apps_lst[] = {
"",
"reboot",
"osver",
"date",
"place",
"cls",
"memory"
};
int apps_count = 7;
void apps_osver()
{
puts("CTA OS v0.1");
puts("\n(c) CTA 2010.\n");
}
void apps_date()
{
puts("Today is ");
puts((char*)clock_weekdays[clock.weekday]);
puts(", "); putc((clock.day/10)+'0');
putc((clock.day%10)+'0');
puts(" "); puts((char*)clock_months[clock.month]);
puts(" "); putc((clock.century/10)+'0');
putc((clock.century%10)+'0');
putc((clock.year/10)+'0');
putc((clock.year%10)+'0');
putc('\n');
}
void apps_place()
{
puts("On your desk, if you didn't notice... \n");
}
void apps_clrscr()
{
clrscr();
}
void apps_memory(const int pn, const char* param[])
{
if (pn<3) {
puts ("Correct syntax: memory [start_address] [end_address] (in hex)\n");
return;
}
byte *start, *end;
byte l1 = strlen(param[1]), l2 = strlen(param[2]);
unsigned int a;
int i; byte *count;
a = 0;
for(i = 0; i < l1; i++) {
switch (param[1][i]) {
case 'a':
case 'A': a = a*16 + 10; break;
case 'b':
case 'B': a = a*16 + 11; break;
case 'c':
case 'C': a = a*16 + 12; break;
case 'd':
case 'D': a = a*16 + 13; break;
case 'e':
case 'E': a = a*16 + 14; break;
case 'f':
case 'F': a = a*16 + 15; break;
default: if (!(param[1][i]>='0' && param[1][i]<='9')) {
puts ((char*)param[1]); puts(" is not a valid hex address.\n");
return;
}
a = a*16 + (param[1][i] - '0');
break;
}
}
start = (byte *)a;
a = 0;
for(i = 0; i < l2; i++) {
switch (param[2][i]) {
case 'a':
case 'A': a = a*16 + 10; break;
case 'b':
case 'B': a = a*16 + 11; break;
case 'c':
case 'C': a = a*16 + 12; break;
case 'd':
case 'D': a = a*16 + 13; break;
case 'e':
case 'E': a = a*16 + 14; break;
case 'f':
case 'F': a = a*16 + 15; break;
default: if (!(param[2][i]>='0' && param[2][i]<='9')) {
puts ((char*)param[2]); puts(" is not a valid hex address.\n");
return;
}
a = a*16 + (param[2][i] - '0');
break;
}
}
end = (byte *)a;
while (start <= end) {
put_hex ((unsigned int) start); puts(": ");
for (count = start; count < start+16; count++) {
putc(hex[*count/16]); putc(hex[*count%16]);
putc(' ');
}
puts(" ");
for (count = start; count < start+16; count++)
putc(*count);
putc('\n');
start+=16;
}
}

81
kernel/shell/shell.c Normal file
View File

@ -0,0 +1,81 @@
#include <conio.h>
#include "apps.h"
void get_str(char *str, int len)
{
kb_key alpha;
int i;
for (i = 0; i<len-1 ; i++) {
text_mode_cursor(cursor_x, cursor_y);
alpha = kb_getkey();
switch (alpha.character) {
case 0x00: --i; break; // Ignore null characters
case 0x7F: --i; break;
case '\b': // Backspace
if (i>0) { // Only backspace our string
if (--cursor_x < 0) { // Begin of row - 1 = End of previous row
cursor_x = 79; cursor_y--;
}
putc_pos(cursor_x, cursor_y, 0);
str[--i] = 0;
}
i--; break;
case '\n': str[i]=0; putc('\n'); return;
default: putc(alpha.character);
str[i] = alpha.character;
str[i+1] = 0;
break;
}
}
}
void shell()
{
char str[256];
char* param[16];
int i, len, params=0;
set_default_colors (0x07, 0x04);
clrscr();
for (;;) {
puts("\n] ");
get_str(str, 256);
len = strlen(str);
// Ignore spaces in front of command
i=0; params = 0;
while (str[i] == ' ') i++;
param[params] = str+i; params++; i++; // Parameter 0 = app itself
for (; i < len && params<16; i++) {
if (str[i] == ' ') str[i]=0;
if (str[i] != 0 && str[i-1]==0) {
param[params] = str+i; params++;
}
}
for (i = 0; strcmp(apps_lst[i], param[0])!=0 && i<apps_count; i++);
switch (i) {
case 0: puts("You must enter a command!\n"); break;
case 1: reboot();
case 2: apps_osver(); break;
case 3: apps_date(); break;
case 4: apps_place(); break;
case 5: apps_clrscr(); break;
case 6: apps_memory(params, (const char**)param); break;
default: puts("Invalid function: "); puts(param[0]);
putc('\n');
break;
}
}
}