Newer
Older
honey-os / src / userland / pic / main.c
#include <stdint.h>
#include <syscalls.h>

#define PTR(x) ((void *)(uintptr_t)x)
#define U32(x) ((uint32_t)(uintptr_t)x)

uint32_t syscall(uint32_t function, uint32_t parameter0, uint32_t parameter1,
                 uint32_t parameter2, uint32_t parameter3) {
    uint32_t esp;
    asm("push %%eax" ::"a"(&&end));
    asm("mov %%esp, %%eax" : "=a"(esp));
    asm("sysenter\n"
        :
        : "a"(function), "b"(parameter0), "c"(parameter1), "d"(parameter2),
          "S"(parameter3), "D"(esp));
end:
    // the 0x1C comes from the number of parameters / local variables do handle
    // this function with care or it will break everything
    asm("add $0x1C, %%esp\n"
        "pop %%ebp\n"
        "ret" ::);
    // don't go here! ret returns with the correct value
    return 0;
}

void installServiceProvider(char *name, void(provider)(void *, uint32_t)) {
    syscall(SYS_REGISTER_FUNCTION, U32(name), U32(provider), 0, 0);
}

uint32_t strlen(char *string) {
    uint32_t size = 0;
    while (*string) {
        string++;
        size++;
    }
    return size;
}

uint32_t ioIn(uint16_t port, uint8_t size) {
    return syscall(SYS_IO_IN, size, port, 0, 0);
}

void ioOut(uint16_t port, uint32_t value, uint8_t size) {
    syscall(SYS_IO_OUT, size, port, value, 0);
}

uint32_t getModule(char *name) {
    return syscall(SYS_GET_SERVICE, U32(name), strlen(name), 0, 0);
}

uint32_t getProvider(uint32_t module, char *name) {
    return syscall(SYS_GET_PROVIDER, module, U32(name), strlen(name), 0);
}

void request(uint32_t module, uint32_t function, void *data, uint32_t size) {
    syscall(SYS_REQUEST, module, function, U32(data), size);
}

void log(char *message) {
    uint32_t module = getModule("log");
    uint32_t provider = getProvider(module, "log");
    request(module, provider, message, strlen(message));
}

#define PIC1 0x20
#define PIC2 0xA0

#define COMMAND_ICW4 0x01
#define COMMAND_SINGLE 0x02
#define COMMAND_INTERVAL4 0x04
#define COMMAND_LEVEL 0x08
#define COMMAND_INIT 0x10
#define DATA(x) PIC##x + 1

#define COMMAND(x, command) ioOut(1, PIC##x, command);

#define BOTH(command, ...)                                                     \
    command(1, __VA_ARGS__);                                                   \
    command(2, __VA_ARGS__);

#define PIC_READ_IRR 0x0A
uint16_t getIRR() {
    ioOut(PIC1, PIC_READ_IRR, 1);
    ioOut(PIC2, PIC_READ_IRR, 1);
    return (ioIn(PIC2, 1) << 8) | ioIn(PIC1, 1);
}

#define PIC_READ_ISR 0x0B
uint16_t getISR() {
    ioOut(PIC1, PIC_READ_ISR, 1);
    ioOut(PIC2, PIC_READ_ISR, 1);
    return (ioIn(PIC2, 1) << 8) | ioIn(PIC1, 1);
}

void irqMaster(uint32_t intNo) {
    uint16_t isr = getISR();
    if (isr) {
        ioOut(PIC1, 0x20, 1);
    }
    bool sentPic2EOI = false;
    for (uint8_t i = 0; i < 16; i++) {
        if (!(isr & (1 << i))) {
            continue;
        }
        if (i >= 8 && !sentPic2EOI) {
            sentPic2EOI = true;
            ioOut(PIC2, 0x20, 1);
        }
        if (i == 1) {
            ioIn(0x60, 1);
            log("keyboard!");
        }
    }
}

void subscribeInterrupt(uint32_t intNo, void *handler) {
    syscall(SYS_SUBSCRIBE_INTERRUPT, intNo, U32(handler), 0, 0);
}

int32_t main() {
    log("setting up interrupt handlers for the PIC");
    for (uint32_t i = 32; i < 48; i++) {
        subscribeInterrupt(i, irqMaster);
    }
}