I have created an operating system from scratch, which accepts interruptions from the keyboard. However, when the keyboard is pressed, the kernel stops working. Any advice is appreciated.
Here's the code:
BootLoader.asm
[BITS 16]
[ORG 0x7C00]
READSECTOR EQU 0x64
READMEMORY EQU 0x7E00
Init:
CLI
XOR AX, AX
MOV DS, AX
MOV ES, AX
MOV SS, AX
MOV SP, 0x7C00
MOV BP, SP
STI
Main:
CALL LoadKernel
CALL SetVBE
CALL DisableInt
CALL EnableA20
CALL SetupGDT
CALL EnterProtectedMode
LoadKernel:
MOV BYTE[BootDrive], DL
MOV BX, 0x02
MOV CX, READSECTOR
MOV DX, READMEMORY
MOV AH, 0x02
MOV AL, CL
MOV CL, BL
MOV BX, DX
MOV CH, 0x00
MOV DH, 0x00
MOV DL, BYTE[BootDrive]
INT 0x13
JC LoadFailed
RET
LoadFailed:
MOV SI, MsgBootFailed
CALL Print
CLI
HLT
Print:
MOV AH, 0x0e
MOV BL, 0x07
MOV BH, 0x00
PrintLoop:
LODSB
TEST AL, AL
JZ PrintEnd
INT 0x10
JMP PrintLoop
PrintEnd:
RET
SetVBE:
MOV AL, 0x13
MOV AH, 0x00
INT 0x10
RET
DisableInt:
MOV AL, 0xff
OUT 0x21, AL
NOP
OUT 0xa1, AL
CLI
RET
EnableA20:
IN AL, 0x92
OR AL, 2
OUT 0x92, AL
RET
SetupGDT:
CLI
PUSHA
LGDT [GDT_TOC]
STI
POPA
RET
GDT_TOC:
DW 8 * 3
DW GDT, 0x0000
GDT:
DW 0x0000, 0x0000, 0x0000, 0x0000
DW 0xFFFF, 0x0000, 0x9A00, 0x00CF
DW 0xFFFF, 0x0000, 0x9200, 0x00CF
EnterProtectedMode:
MOV EAX, CR0
AND EAX, 0x7fffffff
OR EAX, 1
MOV CR0, EAX
JMP 08h:Main32
[BITS 32]
Main32:
MOV AX, 0x10
MOV DS, AX
MOV ES, AX
MOV FS, AX
MOV GS, AX
MOV SS, AX
MOV ESP, 0xffff
CALL RelocKernel
JMP ExecuteKernel
RelocKernel:
MOV ESI, READMEMORY
MOV EDI, 0x200000
MOV ECX, 512 * READSECTOR
CALL memcpy
RET
memcpy:
MOV EAX, [ESI]
ADD ESI, 4
MOV [EDI], EAX
ADD EDI, 4
SUB ECX, 1
JNZ memcpy
RET
ExecuteKernel:
CLI
MOV EBP, 0x200000
;ADD EBP, [EBP 0x18]
CALL EBP
HLT
MsgBootFailed: DB "Kernel Load Failed.", 0x0D, 0x0A, 0x00
BootDrive: DB 0
TIMES 510 - ($ - $$) DB 0
DW 0xAA55
KernelMain.c
#include "KernelMain.h"
int main()
{
InitGDTIDT();
InitPIC();
ASM_STI();
IoWrite8(0x0021, 0xf9);
IoWrite8(0x00a1, 0xef);
for (;;)
{
ASM_HLT();
}
return 0;
}
KernelMain.h
typedef unsigned long size_t;
typedef signed int int32_t;
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;
typedef signed short int16_t;
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned long long uint64_t;
#define ADR_IDT 0x0010f800
#define LIMIT_IDT 0x000007ff
#define ADR_GDT 0x00110000
#define LIMIT_GDT 0x0000ffff
#define ADR_KERNEL 0x00200000
#define LIMIT_KERNEL 0x0007ffff
#define AR_DATA32_RW 0x4092
#define AR_CODE32_ER 0x409a
#define AR_INTGATE32 0x008e
typedef struct
{
uint16_t LimitLow;
uint16_t BaseLow;
uint8_t BaseMid;
uint8_t AccessRight;
uint8_t LimitHigh;
uint8_t BaseHigh;
} SEGMENT_DESCRIPTOR;
typedef struct
{
uint16_t OffsetLow;
uint16_t Selector;
uint8_t DwCount;
uint8_t AccessRight;
uint16_t OffsetHigh;
} GATE_DESCRIPTOR;
void InitGDTIDT();
void SetSegmentDescriptor(SEGMENT_DESCRIPTOR *sd, uint32_t limit, int base, int ar);
void SetGateDescriptor(GATE_DESCRIPTOR *gd, int offset, int selector, int ar);
void InitPIC();
void _inthandler21(int *esp);
void _inthandler27(int *esp);
void _inthandler2c(int *esp);
void _asm_inthandler21(void);
void _asm_inthandler27(void);
void _asm_inthandler2c(void);
Segment.c
#include "KernelMain.h"
void InitGDTIDT()
{
SEGMENT_DESCRIPTOR *gdt = (SEGMENT_DESCRIPTOR *)ADR_GDT;
GATE_DESCRIPTOR *idt = (GATE_DESCRIPTOR *)ADR_IDT;
int i;
for (i = 0; i <= LIMIT_GDT / 8; i )
{
SetSegmentDescriptor(gdt i, 0, 0, 0);
}
SetSegmentDescriptor(gdt 1, 0xffffffff, 0x00000000, AR_DATA32_RW);
SetSegmentDescriptor(gdt 2, LIMIT_KERNEL, ADR_KERNEL, AR_CODE32_ER);
LoadGDT(LIMIT_GDT, ADR_GDT);
for (i = 0; i <= LIMIT_IDT / 8; i )
{
SetGateDescriptor(idt i, 0, 0, 0);
}
LoadIDT(LIMIT_IDT, ADR_IDT);
SetGateDescriptor(idt 0x21, (int)_asm_inthandler21, 2 * 8, AR_INTGATE32);
SetGateDescriptor(idt 0x27, (int)_asm_inthandler27, 2 * 8, AR_INTGATE32);
SetGateDescriptor(idt 0x2c, (int)_asm_inthandler2c, 2 * 8, AR_INTGATE32);
}
void SetSegmentDescriptor(SEGMENT_DESCRIPTOR *sd, uint32_t limit, int base, int ar)
{
if (limit > 0xfffff)
{
ar |= 0x8000;
limit /= 0x1000;
}
sd->LimitLow = limit & 0xffff;
sd->BaseLow = base & 0xffff;
sd->BaseMid = (base >> 16) & 0xff;
sd->AccessRight = ar & 0xff;
sd->LimitHigh = ((limit >> 16) & 0x0f) | ((ar >> 8) & 0xf0);
sd->BaseHigh = (base >> 24) & 0xff;
}
void SetGateDescriptor(GATE_DESCRIPTOR *gd, int offset, int selector, int ar)
{
gd->OffsetLow = offset & 0xffff;
gd->Selector = selector;
gd->DwCount = (ar >> 8) & 0xff;
gd->AccessRight = ar & 0xff;
gd->OffsetHigh = (offset >> 16) & 0xffff;
}
Interrupts.asm
[BITS 32]
GLOBAL _asm_inthandler21, _asm_inthandler27, _asm_inthandler2c
EXTERN _inthandler21, _inthandler27, _inthandler2c
[SECTION .text]
_asm_inthandler21:
PUSH ES
PUSH DS
PUSHAD
MOV EAX,ESP
PUSH EAX
MOV AX,SS
MOV DS,AX
MOV ES,AX
CALL _inthandler21
POP EAX
POPAD
POP DS
POP ES
IRETD
_asm_inthandler27:
PUSH ES
PUSH DS
PUSHAD
MOV EAX,ESP
PUSH EAX
MOV AX,SS
MOV DS,AX
MOV ES,AX
CALL _inthandler27
POP EAX
POPAD
POP DS
POP ES
IRETD
_asm_inthandler2c:
PUSH ES
PUSH DS
PUSHAD
MOV EAX,ESP
PUSH EAX
MOV AX,SS
MOV DS,AX
MOV ES,AX
CALL _inthandler2c
POP EAX
POPAD
POP DS
POP ES
IRETD
Interrupts.c
#include "KernelMain.h"
#define PIC0_ICW1 0x0020
#define PIC0_OCW2 0x0020
#define PIC0_IMR 0x0021
#define PIC0_ICW2 0x0021
#define PIC0_ICW3 0x0021
#define PIC0_ICW4 0x0021
#define PIC1_ICW1 0x00a0
#define PIC1_OCW2 0x00a0
#define PIC1_IMR 0x00a1
#define PIC1_ICW2 0x00a1
#define PIC1_ICW3 0x00a1
#define PIC1_ICW4 0x00a1
void InitPIC()
{
IoWrite8(PIC0_IMR, 0xff);
IoWrite8(PIC1_IMR, 0xff);
IoWrite8(PIC0_ICW1, 0x11);
IoWrite8(PIC0_ICW2, 0x20);
IoWrite8(PIC0_ICW3, 1 << 2);
IoWrite8(PIC0_ICW4, 0x01);
IoWrite8(PIC1_ICW1, 0x11);
IoWrite8(PIC1_ICW2, 0x28);
IoWrite8(PIC1_ICW3, 2);
IoWrite8(PIC1_ICW4, 0x01);
IoWrite8(PIC0_IMR, 0xfb);
IoWrite8(PIC1_IMR, 0xff);
return;
}
void _inthandler21(int *esp)
{
for (int i = 0; i < 320 * 200; i )
{
*((uint8_t *)i) = 1;
}
for (;;)
{
ASM_HLT();
}
}
void _inthandler2c(int *esp)
{
for (int i = 0; i < 320 * 200; i )
{
*((uint8_t *)i) = 2;
}
for (;;)
{
ASM_HLT();
}
}
void _inthandler27(int *esp)
{
for (int i = 0; i < 320 * 200; i )
{
*((uint8_t *)i) = 3;
}
IoWrite8(PIC0_OCW2, 0x67);
return;
}
asm.c
#include "KernelMain.h"
void IoWrite8(uint32_t port, uint8_t data)
{
asm volatile("outb