#ifndef X86_H
#define X86_H

#include <stdbool.h>
#include <stdint.h>

uint64_t rdmsr(uint32_t msr);
void cpuid(uint32_t leaf, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx);
void wrmsr(uint32_t msr, uint64_t value);
bool x86_has_msr();
void x86_arch_init();

void x86_cpu_identification();
int cpuid_get_vendor_string(char* str);

/* Interrupt Descriptor Table */

void idt_init(void);

struct interrupt_descriptor {
    uint16_t address_low;
    uint16_t selector;
    uint8_t ist;
    uint8_t flags;
    uint16_t address_mid;
    uint32_t address_high;
    uint32_t reserved;
} __attribute__((packed));

struct idtr {
    uint16_t limit;
    uint64_t base;
} __attribute__((packed));

// All general-purpose registers (except rsp) as stored on the stack,
// plus the values we pushed (vector number, error code) and the iret frame
// In reverse order because the stack grows downwards.
struct cpu_status {
    uint64_t r15;
    uint64_t r14;
    uint64_t r13;
    uint64_t r12;
    uint64_t r11;
    uint64_t r10;
    uint64_t r9;
    uint64_t r8;
    uint64_t rbp;
    uint64_t rdi;
    uint64_t rsi;
    uint64_t rdx;
    uint64_t rcx;
    uint64_t rbx;
    uint64_t rax;

    uint64_t vector_number;
    uint64_t error_code;

    uint64_t iret_rip;
    uint64_t iret_cs;
    uint64_t iret_flags;
    uint64_t iret_rsp;
    uint64_t iret_ss;
};

struct cpu_status* syscall_handler(struct cpu_status* regs);

#endif