main.c                          Î  #include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "fpu.h"
#include "gdt.h"
#include "gfx.h"
#include "gfx_font.h"
#include "idt.h"
#include "initrd.h"
#include "isr.h"
#include "irq.h"
#include "log.h"
#include "multiboot.h"
#include "paging.h"
#include "panic.h"
#include "pcspkr.h"
#include "ps2kbd.h"
#include "fpu.h"
#include "timer.h"
#include "version.h"
#include "vgatext.h"

void gpf(struct regs_t *regs)
{
    gfx_reset();
    printf("General protection fault!\n");
    printf("EIP before fault: 0x%x\n", regs->eip);
    printf("Error code: 0x%x\n", regs->err_code);
    panic("GPF!");
}

void int80(struct regs_t *regs)
{
    switch(regs->eax)
    {
    case 0:
        panic((const char*)regs->ebx);
        break;
    case 1:
        puts((const char*)regs->ebx);
        break;
    }
}

void div0(struct regs_t *regs)
{
    (void) regs;
    panic("Divide by zero!\n");
}

void nothin(struct regs_t* regs)
{
    (void) regs;
}

void flash_leds(void)
{
    printf("Testing keyboard LED's");

    int n = 0;
    int s = 1;

    while(1)
    {
        ps2kbd_set_leds(PS2_NUM_LOCK);
        timer_delay(HZ/4);
        if(s < 0)
            putchar('\b');
        else
            putchar('.');
        n+=s;
        if(n<=0 || n>=3)
            s=-s;
        ps2kbd_set_leds(PS2_CAPS_LOCK);
        timer_delay(HZ/4);
        if(s < 0)
            putchar('\b');
        else
            putchar('.');
        n+=s;
        if(n<=0 || n>=3)
            s=-s;
        ps2kbd_set_leds(PS2_SCROLL_LOCK);
        timer_delay(HZ/4);
        if(s < 0)
            putchar('\b');
        else
            putchar('.');
        n+=s;
        if(n<=0 || n>=3)
            s=-s;
        ps2kbd_set_leds(PS2_CAPS_LOCK);
        timer_delay(HZ/4);
        if(s < 0)
            putchar('\b');
        else
            putchar('.');
        n+=s;
        if(n<=0 || n>=3)
            s=-s;
    }
}

bool boot(struct multiboot_info_t *hdr, uint32_t magic)
{
    fpu_enable();

    /* load initrd if any, this will also prevent modules from being clobbered by kmalloc */
    initrd_init(hdr);

    /* this should go to port e9, which is the Bochs debug port */
    printf("Testing early I/O\n");

    printf("GFX init\n");
    bool gfx_status = gfx_init((struct vbe_info_t*)hdr->vbe_mode_info);
    //bool gfx_status = false;
    printf("GFX init done.\n");

    /* if graphical initialization fails, fall back to text mode */
    if(!gfx_status)
    {
        vgatext_init();
        printf("Graphics init failed, fell back to VGA text mode.\n");
    }

    if(magic != 0x2BADB002)
    {
        panic("Multiboot magic invalid");
    }

    /* then the descriptor tables so we can do more useful stuff */
    gdt_init();
    idt_init();

    /* install all the interrupt stubs */
    isr_init();
    irq_init();

    /* initialize other drivers */
    timer_init(HZ);
    ps2kbd_init();

    set_interrupt_handler(0, div0);
    set_interrupt_handler(0xd, gpf);
    set_interrupt_handler(0x80, int80);
    set_interrupt_handler(6, nothin);

    paging_init();

    printf("Paging enabled.\n");

    asm("sti");

    printf("Boot finished.\n");

    printf("Kernel version %s: \"%s\"\n", KAPPA_KERNEL_VERSION, KAPPA_KERNEL_CODENAME);

    return gfx_status;
}

void run_gfx_benchmark(void)
{
    const int width = *gfx_width;
    const int height = *gfx_height;

    gfx_reset();

    int startpix = *current_tick;
    for(int i=0;i<1000000;++i)
    {
        int rx = rand() % width;
        int ry = rand() % height;

        gfx_set_foreground(rand() % 0x1000000);
        gfx_drawpixel(rx, ry);
    }
    int endpix = *current_tick;

    gfx_reset();

    int startfill = *current_tick;
    for(int i=0;i<1000;++i)
    {
        gfx_set_background(rand() % 0x1000000);
        gfx_clear();
    }
    int endfill = *current_tick;

    gfx_reset();

    int starttext = *current_tick;
    for(int i=0;i<1000000;++i)
    {
        int rx = rand() % width;
        int ry = rand() % height;
        gfx_set_foreground(rand() % 0x1000000);
        gfx_drawchar(rx, ry, rand()%127+1);
    }
    int endtext = *current_tick;

    gfx_reset();

    int starthline = *current_tick;
    for(int i=0;i<1000000;++i)
    {
        gfx_set_foreground(rand() % 0x1000000);
        gfx_hline(rand() % width, rand() % width, rand() % height);
    }
    int endhline = *current_tick;

    gfx_reset();

    int startvline = *current_tick;
    for(int i=0;i<1000000;++i)
    {
        gfx_set_foreground(rand() % 0x1000000);
        gfx_vline(rand() % height, rand() % height, rand() % width);
    }
    int endvline = *current_tick;

    gfx_reset();

    int startrect = *current_tick;
    for(int i=0;i<10000;++i)
    {
        int x = rand() % width;
        int y = rand() % height;
        int w = rand() % (width - x);
        int h = rand() % (height - y);
        gfx_set_foreground(rand() % 0x1000000);
        gfx_fillrect(x, y, w, h);
    }
    int endrect = *current_tick;

    gfx_reset();

    int startline = *current_tick;
    for(int i=0;i<1000000;++i)
    {
        int x1= rand() % width;
        int x2= rand() % width;
        int y1= rand() % height;
        int y2= rand() % height;
        gfx_set_foreground(rand() % 0x1000000);
        gfx_drawline(x1, y1, x2, y2);
    }
    int endline = *current_tick;

    gfx_reset();

    printf("--- Graphics benchmark results ---\n");
    printf("Ticks for 1,000,000 random pixels: %d\n", endpix-startpix);
    printf("Ticks for 1,000 random fills:      %d\n", endfill-startfill);
    printf("Ticks for 1,000,000 random chars:  %d\n", endtext-starttext);
    printf("Ticks for 1,000,000 random hlines: %d\n", endhline-starthline);
    printf("Ticks for 1,000,000 random vlines: %d\n", endvline-startvline);
    printf("Ticks for 10,000 random rects:     %d\n", endrect-startrect);
    printf("Ticks for 1,000,000 random lines:  %d\n", endline-startline);
    printf("Ticks per second:                  %d\n", HZ);
    printf("Resolution: %dx%dx%d\n", *gfx_width, *gfx_height, *gfx_bpp * 8);
}

static void keyhandler(const struct ps2_keyevent *ev)
{
    if(ev->ascii)
    {
        if(ev->special_keys->ctrl)
        {
            putchar('^');
            putchar(toupper(ev->ascii));
        }
        else
        {
            putchar(ev->ascii);
        }
    }
}

void main(struct multiboot_info_t *hdr, uint32_t magic)
{
    bool gfx_status = boot(hdr, magic);
    initrd_read();
    gfx_set_foreground(0x80FF80);
    printf("Hello, world!\n");
    gfx_set_foreground(GFX_WHITE);

    ps2kbd_set_handler(keyhandler);

    while(1)asm("hlt");

    //char *ptr = 0xA00000;
    //putchar(*ptr);

    printf("Starting linked-in application XRacer...\n");
    //printf("Running graphics benchmark...\n");
    srand(42);

    gfx_reset();

    enum plugin_status;
    struct plugin_api;
    extern enum plugin_status xracer_main(const struct plugin_api*);
    extern void plugin_load(enum plugin_status (*func)(const struct plugin_api*));

    //plugin_load(xracer_main);

    if(gfx_status)
    {
        run_gfx_benchmark();
    }
    flash_leds();
}
