Home > database >  Kernel stops working when an interrupt occurs
Kernel stops working when an interrupt occurs

Time:07-23

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            
  • Related