#ifndef GDT_H
#define GDT_H

#include "types.h"

#define GDT_MAX_ENTRIES 8

// Access byte
#define GDT_AC 1            // Access bit
#define GDT_RW 1 << 1       // Read/Write bit
#define GDT_DC 1 << 2       // Direction bit/Conforming bit
#define GDT_EXEC 1 << 3     // Executable bit
#define GDT_S 1 << 4        // Descriptor type
#define GDT_PRVL_0 0        // Privilege (from 0 to 3)
#define GDT_PRVL_1 1 << 5
#define GDT_PRVL_2 2 << 5
#define GDT_PRVL_3 3 << 5
#define GDT_PR 1 << 7       // Present Bit

// Flags
#define GDT_SZ 1 << 2       // Size bit
#define GDT_GR 1 << 3       // Granularity bit

typedef struct GDT_ENTRY {
  u32 base;
  u32 limit;
  u8 flags;
  u8 access;
} GDT_ENTRY;

struct GDT_REGISTER {
  u16 limit;
  u32 base;
} __attribute__((packed));

typedef struct GDT_TSS {
  u16 previous_task,previous_task_unused;
  u32 esp0;
  u16 ss0, ss0_unused;
  u32 esp1;
  u16 ss1, ss1_unused;
  u32 esp2;
  u16 ss2, ss2_unused;
  u32 cr3;
  u32 eip;
  u32 eflags;
  u32 eax;
  u32 ecx;
  u32 edx;
  u32 ebx;
  u32 esp;
  u32 ebp;
  u32 esi;
  u32 edi;
  u16 es, es_reserved;
  u16 cs, cs_reserved;
  u16 ss, ss_reserved;
  u16 ds, ds_reserved;
  u16 fs, fs_reserved;
  u16 gs, gs_reserved;
  u16 ldtss, ldtss_reserved;
  u16 t_reserved, io_map;
} __attribute__((packed)) GDT_TSS;

/**
 * Copy GDT in memory
 */
void gdt_memcpy();

/**
 * Write a GDT entry at address addr
 */
void gdt_write_entry(GDT_ENTRY entry, u32 id);

int gdt_user_ds_base();

#endif