#ifndef GDT_H
#define GDT_H

#include "lib/common/common.h"
#include "../../Kdriver/screen/printk.h"

#pragma pack(push, 1)
struct gdt_entry_struct
{
    uint16_t limit_low;           // The lower 16 bits of the limit.
    uint16_t base_low;            // The lower 16 bits of the base.
    uint8_t  base_middle;         // The next 8 bits of the base.
    uint8_t  access;              // Access flags, determine what ring this segment can be used in.
    uint8_t  granularity;
    uint8_t  base_high;           // The last 8 bits of the base.
};

typedef struct gdt_entry_struct gdt_entry_t;

// This struct describes a GDT pointer. It points to the start of
// our array of GDT entries, and is in the format required by the
// lgdt instruction.
#pragma pack(push, 1)
struct gdt_ptr_struct
{
    uint16_t limit;               // The upper 16 bits of all selector limits.
    uint64_t base;                // The address of the first gdt_entry_t struct.
};

typedef struct gdt_ptr_struct gdt_ptr_t;

void init_gdt();
void gdt_set_gate(int32_t,uint32_t,uint32_t,uint8_t,uint8_t);

#pragma pack(push, 1)
struct tss_entry_struct {
    uint32_t reserved_0;
    uint32_t rsp0_low;
    uint32_t rsp0_high;
    uint64_t rsp1;
    uint64_t rsp2;
    uint64_t reserved_1;
    uint64_t ist1;
    uint64_t ist2;
    uint64_t ist3;
    uint64_t ist4;
    uint64_t ist5;
    uint64_t ist6;
    uint64_t ist7;
    uint64_t reserved_2;
    uint16_t reserved_3;
    uint16_t io_map_base_address;
};

typedef struct tss_entry_struct tss_entry_t;

void write_tss(int32_t num, uint64_t rsp0);
void set_kernel_stack(uint64_t stack);

#endif
