How to load IDT?
Asked Answered
U

1

6

I'm working on writing own little os. I already done booting, entering protected mode, some text printing and serial communication with qemu. I've been trying to add interrupts for over two days. I was looking everywhere including other systems sources. No I've got code below and qemu (I don't know why) shuts down. I including geust errors from qemu.

This is my main file kernel.cpp

__asm__ (".pushsection .text.start\r\n" \
          "jmp main\r\n" \
          ".popsection\r\n");

#include <stdbool.h>
#include "utils/debug.h"
#include "drivers/display.h"
#include "drivers/serial.h"
#include "drivers/keyboard.h"
#include "drivers/pic.h"
#include "interrupt/interrupt.h"


void initDrivers(){
    serial::init();
    pic::init();
    interrupt::init();
    interrupt::enable();
    terminal_initialize();
}

int main() {
    initDrivers();
    terminal_setcolor(VGA_COLOR_WHITE);
    terminal_writestring("Hello!");

    debug::println("after println");

    bool alive = true;
    while(alive) {

    }

    return 0;
}

PIC driver pic.cpp and pic.h

#include "pic.h"
#include <stddef.h>
#include <stdint.h>
#include "IO.h"
#include "../utils/debug.h"
/*
* IMR - Interrupt Mask Register
* IRR - Interrupt Request Register
* ISR - In-Service Register or Interrupt Service Routine
*
*/



namespace pic {
    static const uint16_t PIC1_PORT         = 0x20; // I/O offset address for master PIC
    static const uint16_t PIC2_PORT         = 0xA0; // I/O offset address for slave PIC
    static const uint16_t PIC1_SPORT        = 0x21; // I/O offset address for master PIC data
    static const uint16_t PIC2_SPORT        = 0xA1; // I/O offset address for slave PIC data
    static const uint8_t OCW3_READ_IRR      = 0x0A; // OCW3 irq ready next CMD read
    static const uint8_t OCW3_READ_ISR      = 0x0B; // OCW3 irq service next CMD read

    void init(){
        outb(PIC1_PORT, 0x11);      // Sending ICW1 to first PIC (starting initialization)
        io_wait();                  // Waiting for PIC to process
        outb(PIC2_PORT, 0x11);      // Sending ICW1 to second PIC
        io_wait();                  // Waiting for PIC to process
        outb(PIC1_SPORT, 0x20);     // Sending ICW2 to first PIC (Mapping IRQs)
        io_wait();                  // Waiting for PIC to process
        outb(PIC2_SPORT, 0x28);     // Sending ICW2 to second PIC
        io_wait();                  // Waiting for PIC to process
        outb(PIC1_SPORT, 4);        // Sending ICW3 to first PIC, "there is a second one - slave" (0000 0100)
        io_wait();                  // Waiting for PIC to process
        outb(PIC2_SPORT, 2);        // Sending ICW3 to second PIC "You are slave" (0000 0010)
        io_wait();                  // Waiting for PIC to process

        outb(PIC1_SPORT, 1);        // Sending ICW4 to first PIC putting it into 80x86 mode (0000 0001)
        io_wait();                  // Waiting for PIC to process
        outb(PIC2_SPORT, 1);        // Sending ICW4 to second PIC putting it into 80x86 mode (0000 0001)
        io_wait();                  // Waiting for PIC to process

        debug::println("PIC initialized!");
    }

    uint16_t __getIrqReg(uint8_t ocw3) {
        outb(PIC1_SPORT, ocw3);
        outb(PIC2_SPORT, ocw3);
        return (inb(PIC2_SPORT) << 8) | inb(PIC1_SPORT);
    }

    uint16_t getIRR() {
        return __getIrqReg(OCW3_READ_IRR);
    }

    uint16_t getISR() {
        return __getIrqReg(OCW3_READ_ISR);
    }

    void ack(uint8_t irq) {
        /* write EOI */

        if (irq >= 16) return; // It's not a valid irq
        if (irq >= 8) outb(PIC2_SPORT, 0x20); // It's a PIC2

        // PIC1 EOI must be called anyway
        outb(PIC1_SPORT, 0x20);
    }

    void mask(uint8_t irq, bool enable) {
        uint16_t port;

        if (irq < 8) port = PIC1_SPORT;
        else if (irq < 16) {
            port = PIC2_SPORT;
            irq -= 8;
        } else return;

        uint8_t value = inb(port);
        wait(150);

        if (enable) value = value & ~(1 << irq);
        else value = value | (1 << irq);

        outb(port, value);
        wait(150);
    }
}

header:

#ifndef PIC_H
#define PIC_H

#include <stdint.h>

namespace pic {
    void init();
    uint16_t getIRR();
    uint16_t getISR();
    void ack(uint8_t irq);
    void mask(uint8_t irq, bool enabled);
}

#endif

All setup for IDT idt.cpp

#include <stdint.h>

extern "C" {
    // CPU Exceptions https://wiki.osdev.org/Exceptions
    extern void isr_0(void);    // Divide By Zero
    extern void isr_1(void);    // Debug
    extern void isr_2(void);    // Non-Maskable Interrupt
    extern void isr_3(void);    // Breakpoint
    extern void isr_4(void);    // Overflow
    extern void isr_5(void);    // Bound Range Exceeded
    extern void isr_6(void);    // Invalid Opcode
    extern void isr_7(void);    // Device Not Avaible
    extern void isr_8(void);    // Double Fault
    extern void isr_9(void);    // Coprocessor Segment Overrun (Old - out of use)
    extern void isr_10(void);   // Invalid TTS
    extern void isr_11(void);   // Segment Not Present
    extern void isr_12(void);   // Stack Segment Fault
    extern void isr_13(void);   // General Protection Fault
    extern void isr_14(void);   // Page Fault
    extern void isr_16(void);   // x87 Floating-Point Exception
    extern void isr_17(void);   // Aligment Check
    extern void isr_18(void);   // Machine Check
    extern void isr_19(void);   // SIMD Floating Point Exception
    extern void isr_20(void);   // Virtualization Exception
    extern void isr_30(void);   // Security Exception

    // IRQs https://wiki.osdev.org/Interrupts#General_IBM-PC_Compatible_Interrupt_Information
    extern void isr_32(void);   // Programmable Interrupt Timer
    extern void isr_33(void);   // Keyboard
    extern void isr_34(void);   // Used Internally (Never Raised)
    extern void isr_35(void);   // COM2
    extern void isr_36(void);   // COM1
    extern void isr_37(void);   // LPT2
    extern void isr_38(void);   // Floppy Disk
    extern void isr_39(void);   // LPT1
    extern void isr_40(void);   // CMOS RTC
    extern void isr_41(void);   // Peripherals
    extern void isr_42(void);   // Peripherals
    extern void isr_43(void);   // Peripherals
    extern void isr_44(void);   // PS/2 Mouse
    extern void isr_45(void);   // FPU / Coprocessor / Inter-processor
    extern void isr_46(void);   // Primary ATA Hard Disk
    extern void isr_47(void);   // Seconadry ATA Hard Disk


    extern void syscallHandler(void);
    extern void isr_49(void);
    extern void isr_50(void);
}

/*  IDT - Interrupt Descriptor Table https://wiki.osdev.org/IDT
*   offset - tells where Interrupt Service Routine Is Located
*   selector - something like properties
*   flags:
*       |  7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
*       +---+---+---+---+---+---+---+---+
*       | P |  DPL  | S |    GateType   |
*       +---+---+---+---+---+---+---+---+
*       P - Present (0 if unused)
*       DPL - Sort of permission to call`
*       Storage Segment - We want it 0
*       GateType - Trap, Interrupt, Task
*/
struct idt_entry {
    uint16_t offset_low;
    uint16_t selector;
    uint8_t unused;
    uint8_t flags;
    uint16_t offset_high;
};

#define IDT_ENTRY(offset, selector, flags) { \
    (uint16_t)((uintptr_t)(offset) & 0xFFFF), \
    (selector), \
    0, \
    (flags), \
    (uint16_t)(((uintptr_t)(offset) >> 16) & 0xFFFF) \
}

#define IDT_INTERRUPT_GATE 0xE
#define IDT_TRAP_GATE 0xF
#define IDT_RING0 (0 << 5)
#define IDT_RING3 (3 << 5)
#define IDT_PRESENT (1 << 7)

extern "C" {
    idt_entry idt[] = {
        IDT_ENTRY(isr_0, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_1, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_2, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_3, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_4, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_5, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_6, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_7, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_8, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_9, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_10, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_11, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_12, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_13, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_14, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(0, 0, 0),
        IDT_ENTRY(isr_16, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_17, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_18, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_19, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_20, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),

        IDT_ENTRY(0, 0, 0),
        IDT_ENTRY(0, 0, 0),
        IDT_ENTRY(0, 0, 0),
        IDT_ENTRY(0, 0, 0),
        IDT_ENTRY(0, 0, 0),
        IDT_ENTRY(0, 0, 0),
        IDT_ENTRY(0, 0, 0),
        IDT_ENTRY(0, 0, 0),
        IDT_ENTRY(0, 0, 0),
        IDT_ENTRY(0, 0, 0),
        IDT_ENTRY(0, 0, 0),

        IDT_ENTRY(isr_32, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_33, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_34, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_35, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_36, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_37, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_38, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_39, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_40, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_41, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_42, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_43, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_44, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_45, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_46, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),
        IDT_ENTRY(isr_47, 0x8, IDT_INTERRUPT_GATE | IDT_RING0 | IDT_PRESENT),

        //IDT_ENTRY(syscallHandler, 0x8, IDT_TRAP_GATE | IDT_RING3 | IDT_PRESENT),
        IDT_ENTRY(isr_49, 0x8, IDT_INTERRUPT_GATE | IDT_RING3 | IDT_PRESENT),
        IDT_ENTRY(isr_50, 0x8, IDT_INTERRUPT_GATE | IDT_RING3 | IDT_PRESENT),
    };

    uint16_t idt_size = sizeof(idt) - 1;
}

File that glues that together interrupt.cpp and interrupt.h (In that file there is a function that causes crashes, but i will explain it after all files.)

#include "interrupt.h"
#include "signals.h"
#include <stdint.h>
#include "../utils/debug.h"
#include "../drivers/IO.h"

#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21
#define PIC2_COMMAND 0xA0
#define PIC2_DATA 0xA1

#define PIC_EOI 0x20

#define EX_DEVIDE_BY_ZERO 0
#define EX_DEBUG 1
#define EX_NON_MASKABLE_INTERRUPT 2
#define EX_BREAKPOINT 3
#define EX_OVERFLOW 4
#define EX_BOUND_RANGE_EXCEEDED 5
#define EX_INVALID_OPCODE 6
#define EX_DEVICE_NOT_AVAILABLE 7
#define EX_DOUBLE_FAULT 8
#define EX_COPROCESSOR_SEGMENT_OVERRUN 9
#define EX_INVAILD_TSS 10
#define EX_SEGMENT_NOT_PRESENT 11
#define EX_STACK_SEGMENT_FAULT 12
#define EX_GENERAL_PROTECTION_FAULT 13
#define EX_PAGE_FAULT 14
#define EX_X87_FLOATING_POINT_EXCEPTION 16
#define EX_ALIGNMENT_CHECK 17
#define EX_MACHINE_CHECK 18
#define EX_SIMD_FLOATING_POINT_EXCEPTION 19
#define EX_VIRTUALIZATION_EXCEPTION 20

const char *exception_messages[] = {
    "Division By Zero",
    "Debug",
    "Non Maskable Interrupt",
    "Breakpoint",
    "Into Detected Overflow",
    "Out of Bounds",
    "Invalid Opcode",
    "No Coprocessor",

    "Double Fault",
    "Coprocessor Segment Overrun",
    "Bad TSS",
    "Segment Not Present",
    "Stack Fault",
    "General Protection Fault",
    "Page Fault",
    "Unknown Interrupt",

    "Coprocessor Fault",
    "Alignment Check",
    "Machine Check",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",

    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved"
};

void (*interrupt::irqHandlers[16])(int) = {0};

void interrupt::init(){
    __asm__ (
        "push $idt      \r\n" \
        "pushw idt_size \r\n" \
        "lidt (%esp)    \r\n"
    );
}

void interrupt::disable() {
    asm volatile ("cli");
}

void interrupt::enable() {
    asm volatile ("sti");
}

extern "C" {
    volatile unsigned long signalPending = 0;
}

static bool handleUserspaceException(const InterruptContext* context) {
    siginfo_t siginfo = {};
    switch (context->interrupt) {
    case EX_DEVIDE_BY_ZERO:
        siginfo.si_signo = SIGFPE;
        siginfo.si_code = FPE_INTDIV;
        siginfo.si_addr = (void*) context->eip;
        break;
    case EX_DEBUG:
    case EX_BREAKPOINT:
        siginfo.si_signo = SIGTRAP;
        siginfo.si_code = TRAP_BRKPT;
        siginfo.si_addr = (void*) context->eip;
        break;
    case EX_OVERFLOW:
    case EX_BOUND_RANGE_EXCEEDED:
    case EX_STACK_SEGMENT_FAULT:
    case EX_GENERAL_PROTECTION_FAULT:
        siginfo.si_signo = SIGSEGV;
        siginfo.si_code = SI_KERNEL;
        siginfo.si_addr = (void*) context->eip;
        break;
    case EX_INVALID_OPCODE:
        siginfo.si_signo = SIGILL;
        siginfo.si_code = ILL_ILLOPC;
        siginfo.si_addr = (void*) context->eip;
        break;
    case EX_PAGE_FAULT:
        siginfo.si_signo = SIGSEGV;
        siginfo.si_code = SEGV_MAPERR;
        asm ("mov %%cr2, %0" : "=r"(siginfo.si_addr));
        break;
    case EX_X87_FLOATING_POINT_EXCEPTION:
    case EX_SIMD_FLOATING_POINT_EXCEPTION:
        siginfo.si_signo = SIGFPE;
        siginfo.si_code = FPE_FLTINV;
        siginfo.si_addr = (void*) context->eip;
        break;
    default:
        return false;
    }

    //Process::current->raiseSignal(siginfo);
    return true;
}

extern "C" InterruptContext* handleInterrupt(InterruptContext* context) {
    InterruptContext* newContext = context;

    if (context->interrupt <= 31 && context->cs != 0x8) {
        if (!handleUserspaceException(context)) goto handleKernelException;
    } else if (context->interrupt <= 31) { // CPU Exception
handleKernelException:
        debug::print("Exception ");
        debug::print(context->interrupt);
        debug::print(" (");
        debug::print(exception_messages[context->interrupt]);
        debug::println(") occurred!");

        debug::print("eax: 0x");
        debug::print(context->eax);
        debug::print(", ebx: 0x");
        debug::print(context->ebx);
        debug::print(", ecx: 0x");
        debug::print(context->ecx);
        debug::print(", edx: 0x");
        debug::println(context->edx);

        debug::print("edi: 0x");
        debug::print(context->edi);
        debug::print(", esi: 0x");
        debug::print(context->esi);
        debug::print(", ebp: 0x");
        debug::print(context->ebp);
        debug::print(", error: 0x");
        debug::println(context->error);

        debug::print("eip: 0x");
        debug::print(context->eip);
        debug::print(", cs: 0x");
        debug::print(context->cs);
        debug::print(", eflags: 0x");
        debug::println(context->eflags);
        if (context->cs != 0x8) {
            debug::print("ss: 0x");
            debug::print(context->ss);
            debug::print(", esp: 0x");
            debug::println(context->esp);
        }
        // Halt the cpu
        while (true) asm volatile ("cli; hlt");
    } else if (context->interrupt <= 47) { // IRQ
        int irq = context->interrupt - 32;
        if (irq == 0) {
            //newContext = Process::schedule(context);
        }

        if (interrupt::irqHandlers[irq]) {
            interrupt::irqHandlers[irq](irq);
        }

        // Send End of Interrupt
        if (irq >= 8) {
            outb(PIC2_COMMAND, PIC_EOI);
        }
        outb(PIC1_COMMAND, PIC_EOI);
    } else if (context->interrupt == 0x32) {
        //newContext = Signal::sigreturn(context);
        debug::println("Keyboard!!");
    } else {
        debug::print("Unknown interrupt ");
        debug::print(context->interrupt);
        debug::println("!");
    }
    return newContext;
}

header:

#ifndef INTERRUPS_H
#define INTERRUPS_H

#include <stdint.h>

extern "C" volatile unsigned long signalPending;

namespace Signal {
    static inline bool isPending() { return signalPending; }
}

struct InterruptContext {
    uint32_t eax;
    uint32_t ebx;
    uint32_t ecx;
    uint32_t edx;
    uint32_t esi;
    uint32_t edi;
    uint32_t ebp;

    uint32_t interrupt;
    uint32_t error;

    // These are pushed by the cpu when an interrupt happens.
    uint32_t eip;
    uint32_t cs;
    uint32_t eflags;

    // These are only valid if the interrupt came from Ring 3
    uint32_t esp;
    uint32_t ss;
};

union sigval {
    int sival_int;
    void* sival_ptr;
};

typedef __UINT64_TYPE__ __uid_t;
typedef struct {
    int si_signo;
    int si_code;
    int si_pid;
    __uid_t si_uid;
    void* si_addr;
    int si_status;
    union sigval si_value;
} siginfo_t;

namespace interrupt {
    extern void (*irqHandlers[])(int);
    void init();
    void disable();
    void enable();
}

#endif

And finally Assembly code intr.s

.section .text

.macro isr no
.global isr_\no
isr_\no:
    push $0 # no error code
    push $\no
    jmp commonHandler
.endm

.macro isr_error_code no
.global isr_\no
isr_\no:
    # an error code was already pushed
    push $\no
    jmp commonHandler
.endm

commonHandler:
    cld

    # Push registers
    push %ebp
    push %edi
    push %esi
    push %edx
    push %ecx
    push %ebx
    push %eax

    # Switch to kernel data segment
    mov $0x10, %ax
    mov %ax, %ds
    mov %ax, %es

    mov %esp, %eax
    and $(~0xFF), %esp # Align the stack
    sub $12, %esp
    push %eax

    call handleInterrupt
    mov %eax, %esp

    # Check whether signals are pending.
    mov signalPending, %ebx
    test %ebx, %ebx
    jz 1f

    # Don't handle signals when returning to kernelspace.
    mov 40(%esp), %ebx # cs
    cmp $0x8, %ebx
    je 1f

    and $(~0xFF), %esp # Align the stack
    sub $12, %esp
    push %eax
    # call handleSignal
    mov %eax, %esp

    # Switch back to user data segment
1:  mov $0x23, %ax
    mov %ax, %ds
    mov %ax, %es

    pop %eax
    pop %ebx
    pop %ecx
    pop %edx
    pop %esi
    pop %edi
    pop %ebp

    # Remove error code and interrupt number from stack
    add $8, %esp

    iret

# CPU Exceptions
isr 0             # Devide-by-zero Error
isr 1             # Debug
isr 2             # Non-maskable Interrupt
isr 3             # Breakpoint
isr 4             # Overflow
isr 5             # Bound Range Exceeded
isr 6             # Invalid Opcode
isr 7             # Device Not Available
isr_error_code 8  # Double Fault
isr 9             # Coprocessor Segment Overrun
isr_error_code 10 # Invalid TSS
isr_error_code 11 # Segment Not Present
isr_error_code 12 # Stack-Segement Fault
isr_error_code 13 # General Protection Fault
isr_error_code 14 # Page Fault
#isr 15           # Reserved
isr 16            # x87 Floating-Point Exception
isr_error_code 17 # Alignment Check
isr 18            # Machine Check
isr 19            # SIMD Floating-Point Exception
isr 20            # Virtualization Exception

# IRQs
isr 32
isr 33
isr 34
isr 35
isr 36
isr 37
isr 38
isr 39
isr 40
isr 41
isr 42
isr 43
isr 44
isr 45
isr 46
isr 47

#isr 48 # Syscall
isr 49 # Schedule
isr 50 # sigreturn

.global beginSigreturn
beginSigreturn:
    # This section is mapped in all user address spaces. When a userspace
    # program returns from a signal handler it will return to this address and
    # and then perform a sigreturn.
    int $0x32
.global endSigreturn
endSigreturn:

Now compile.sh that I'm using to macro compilation (I know about makefiles I will trying to involve them)

if [ $# -eq 0 ]; then
    nasm -g -f elf32 -F dwarf -o boot.o bootloader/bootloader.asm
    ld -melf_i386 -Ttext=0x7c00 -nostdlib --nmagic -o boot.elf boot.o
    objcopy -O binary boot.elf boot.bin

    g++ -std=c++14 -g -c -m32 -ffreestanding kernel.cpp
    g++ -std=c++14 -g -c -m32 -ffreestanding drivers/display.cpp
    g++ -std=c++14 -g -c -m32 -ffreestanding drivers/serial.cpp
    g++ -std=c++14 -g -c -m32 -ffreestanding drivers/keyboard.cpp
    g++ -std=c++14 -g -c -m32 -ffreestanding drivers/pic.cpp
    g++ -std=c++14 -g -c -m32 -ffreestanding interrupt/interrupt.cpp
    g++ -std=c++14 -g -c -m32 -ffreestanding interrupt/idt.cpp
    g++ -std=c++14 -g -c -m32 -ffreestanding utils/debug.cpp
    g++ -m32 -c interrupt/intr.s -o intr.o

    ld -r -m elf_i386 kernel.o display.o serial.o keyboard.o pic.o interrupt.o idt.o intr.o debug.o -o main.o
    ld -melf_i386 -Tlinker.ld -nostdlib --nmagic -o main.elf main.o

    objcopy -O binary main.elf main.bin

    dd if=/dev/zero of=disk.img bs=512 count=2880
    dd if=boot.bin of=disk.img bs=512 conv=notrunc
    dd if=main.bin of=disk.img bs=512 seek=1 conv=notrunc

    rm -rf boot.o
    rm -rf kernel.o
    rm -rf serial.o
    rm -rf main.o
    rm -rf keyboard.o
    rm -rf debug.o
    rm -rf pic.o
    rm -rf display.o

    rm -rf boot.bin
    rm -rf kernel.bin
else
    if [ $1 = "clean" ]; then
        rm -rf boot.o
        echo successfully removed boot.o!
        rm -rf kernel.o
        echo successfully removed kernel.o!
        rm -rf IO.o
        echo successfully removed IO.o!
        rm -rf main.o
        echo successfully removed main.o!

        rm -rf boot.bin
        echo successfully removed boot.bin!
        rm -rf kernel.bin
        echo successfully removed kernel.bin!

        rm -rf boot.elf
        echo successfully removed boot.elf!
        rm -rf kernel.elf
        echo successfully removed kernel.elf!
        rm -rf disk.img
        echo successfully removed disk.img!
        echo Cleanup done!
    fi
fi

And the last ones run.sh and rund.sh that I'm using to macro qemu etc.

qemu-system-i386 -fda disk.img -d guest_errors & \
echo "Reading kernel log (Ctrl+C for exit)"
tail -f virtual.log

qemu-system-i386 -m 1024 -fda disk.img -S -s &
gdb main.elf  \
        -ex 'target remote localhost:1234' \
        -ex 'layout src' \
        -ex 'layout reg' \
        -ex 'break main' \
        -ex 'continue'

I'm including also qemu guest errors output

EAX=0000be44 EBX=0000be44 ECX=00090000 EDX=000003f8
ESI=00000000 EDI=00000000 EBP=bee00000 ESP=0008ffba
EIP=ffc80000 EFL=00000016 [----AP-] CPL=0 II=0 A20=1 SMM=0 HLT=0
ES =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
CS =0008 00000000 ffffffff 00cf9a00 DPL=0 CS32 [-R-]
SS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
DS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
FS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
GS =0010 00000000 ffffffff 00cf9300 DPL=0 DS   [-WA]
LDT=0000 00000000 0000ffff 00008200 DPL=0 LDT
TR =0000 00000000 0000ffff 00008b00 DPL=0 TSS32-busy
GDT=     00007d35 00000017
IDT=     0000bee0 00000000
CR0=00000011 CR2=00000000 CR3=00000000 CR4=00000000
DR0=00000000 DR1=00000000 DR2=00000000 DR3=00000000 
DR6=ffff0ff0 DR7=00000400
CCS=0000268b CCD=0000be44 CCO=ADDL    
EFER=0000000000000000
FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80
FPR0=0000000000000000 0000 FPR1=0000000000000000 0000
FPR2=0000000000000000 0000 FPR3=0000000000000000 0000
FPR4=0000000000000000 0000 FPR5=0000000000000000 0000
FPR6=0000000000000000 0000 FPR7=0000000000000000 0000
XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000
XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000
XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000
XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000

So like I said. Code fragment that causes shutdowns is in interrupt.cpp

void interrupt::init(){
    __asm__ (
        "push $idt      \r\n" \
        "pushw idt_size \r\n" \
        "lidt (%esp)    \r\n"
    );
} 

If I comment this one, os working, but there is no interrupts. I have no ideas how to fix it. Any ideas?

Unhandled answered 25/2, 2018 at 2:44 Comment(4)
You really expect someone to read all this?Proceleusmatic
I tried to include all code that might be useful.Unhandled
@Old, ironically, the usual complaint is that people don't include enough.Balancer
@Proceleusmatic : I'm glad to see someone provide all the code and build method. often the Osdev related questions come down to seeing all the code. Although long, I applaud this OP for making it all available. they get +1 from me. on that alone lolLandonlandor
B
8

The problem is that you don't restore the stack pointer in interrupt::init, so the return from that function returns into the weeds.

The simplest, but poor, fix for this is to simply add

    add $6, %esp

after lidt.

A much better solution is to change it to not modify esp within the inline assembly.

void interrupt::init()
{
    struct __attribute__((packed)) { uint16_t size; uint32_t idt; }
        descr  = { idt_size, idt };
    __asm__ __volatile__ ("lidt %0" : : "m"(descr));
}

Although I appreciate your including all your code, I didn't carefully read all of it; I simply answered the first problem I noticed, so you may still have problems.

Balancer answered 25/2, 2018 at 3:47 Comment(1)
There may be a compiler intrinsic, __builtin_ia32_lidt, which would be preferable.Balancer

© 2022 - 2024 — McMap. All rights reserved.