Viliam Holly
Viliam Holly

Reputation: 182

CPU Reset When Remapping the PIC Using Limine Bootloader in My OS

I'm currently developing an operating system that uses the limine bootloader and follows the limine boot protocol. However, I've encountered an issue: when I call init_PIC(), the CPU resets immediately on the first line inside PIC_remap(). I suspect this might be due to a fatal error during PIC remapping.

Below is the relevant code:


pic.c

#include "pic.h"

#include "../drivers/ports.h"

#define PIC1 0x20  // master PIC
#define PIC2 0xA0  // slave PIC
#define PIC1_COMMAND PIC1
#define PIC1_DATA (PIC1 + 1)
#define PIC2_COMMAND PIC2
#define PIC2_DATA (PIC2 + 1)

#define ICW1_ICW4 0x01
#define ICW1_SINGLE 0x02
#define ICW1_INTERVAL4 0x04
#define ICW1_LEVEL 0x08
#define ICW1_INIT 0x10

#define ICW4_8086 0x01
#define ICW4_AUTO 0x02
#define ICW4_BUF_SLAVE 0x08
#define ICW4_BUF_MASTER 0x0C
#define ICW4_SFNM 0x10

static inline void io_wait(void) { __asm__ __volatile__("outb %%al, $0x80" : : "a"(0)); }

static void PIC_remap(int master_off, int slave_off) {
    outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
    io_wait();
    outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
    io_wait();
    outb(PIC1_DATA, master_off);  // ICW2: Master PIC
    io_wait();
    outb(PIC2_DATA, slave_off);  // ICW2: Slave PIC
    io_wait();
    outb(PIC1_DATA, 4);  // ICW3: tell Master PIC that there is a slave PIC at IRQ2
    io_wait();
    outb(PIC2_DATA, 2);  // ICW3: tell Slave PIC its cascade identity
    io_wait();

    outb(PIC1_DATA, ICW4_8086);  // ICW4: have the PICs use 8086 mode
    io_wait();
    outb(PIC2_DATA, ICW4_8086);
    io_wait();

    // Unmask both PICs
    outb(PIC1_DATA, 0);
    outb(PIC2_DATA, 0);
}

void init_PIC(void) {
    __asm__ __volatile__("cli");  // disable interrupts
    PIC_remap(0x20, 0x28);
    __asm__ __volatile__("sti");  // enable interrupts
}

ports.c (driver for port I/O)

#include "ports.h"

#include <stdint.h>

inline uint8_t inb(uint16_t port) {
    uint8_t ret;
    __asm__ __volatile__("inb %w1, %b0" : "=a"(ret) : "Nd"(port) : "memory");
    return ret;
}

inline void outb(uint16_t port, uint8_t val) {
    __asm__ __volatile__("outb %b0, %w1" : : "a"(val), "Nd"(port) : "memory");
}

kmain.c

#include <stddef.h>

#include "drivers/screen.h"
#include "interrupts/idt.h"
#include "interrupts/pic.h"
#include "limine.h"
#include "misc.h"

__attribute__((used,
               section(".limine_requests_start"))) static volatile LIMINE_REQUESTS_START_MARKER;
__attribute__((used, section(".limine_requests_end"))) static volatile LIMINE_REQUESTS_END_MARKER;
__attribute__((used, section(".limine_requests"))) static volatile LIMINE_BASE_REVISION(3);

__attribute__((used, section(".limine_requests"))) static volatile struct limine_framebuffer_request
    framebuffer_request = {.id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0};

void kmain(void) {
    if (!LIMINE_BASE_REVISION_SUPPORTED) {
        stop();
    }

    // don't support multiple framebuffers
    if (!framebuffer_request.response || framebuffer_request.response->framebuffer_count > 1) {
        stop();
    }

    init_screen(framebuffer_request.response->framebuffers[0]);
    set_font_scale(2);
    init_idt();
    init_PIC();

    stop();
}

Additional Details

For an MCVE, please refer to the following GitHub repo.

Upvotes: 1

Views: 72

Answers (0)

Related Questions