CTAOS v1
This commit is contained in:
parent
7cafad0682
commit
c90c6dc692
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,7 +5,7 @@
|
|||||||
# Compiled Object files
|
# Compiled Object files
|
||||||
*.slo
|
*.slo
|
||||||
*.lo
|
*.lo
|
||||||
*.o
|
#*.o
|
||||||
*.obj
|
*.obj
|
||||||
|
|
||||||
# Precompiled Headers
|
# Precompiled Headers
|
||||||
|
22
compile.bat
Normal file
22
compile.bat
Normal 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
|
78
gdt.c
Normal file
78
gdt.c
Normal 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
62
idt.c
Normal 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
152
include/console.h
Normal 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
104
include/system.h
Normal 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
37
init.c
Normal 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
118
irq.c
Normal 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
163
isrs.c
Normal 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
BIN
kernel.bin
Normal file
Binary file not shown.
209
keyus.c
Normal file
209
keyus.c
Normal 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
25
link.ld
Normal 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
449
loader.asm
Normal 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:
|
65
main.c
Normal file
65
main.c
Normal 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;
|
||||||
|
}
|
52
timer.c
Normal file
52
timer.c
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user