admin管理员组

文章数量:1242886

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

  • The reset occurs immediately when entering PIC_remap(), specifically on the first outb call.
  • Interrupts are disabled before calling PIC_remap(), so that shouldn't be the issue.

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

本文标签: gccCPU Reset When Remapping the PIC Using Limine Bootloader in My OSStack Overflow