#include "clib.h"
#include "i386.h"
#include "phmem.h"
#include "systab.h"


#define IS_NULL_DESCRIPTOR(d) ((d).access.system.type == 0)
#define MARK_USED_DESCRIPTOR(d) ((d).access.system.type = 1)
#define MARK_FREE_DESCRIPTOR(d) ((d).access.system.type = 0)


static inline void
lidt (lidt_t *p)
{
  asm volatile ("lidt %0" : : "m" (*p));
}
/*
static inline void
sidt (lidt_t *p)
{
  asm volatile ("sidt %0" : "=m" (*p) : : "memory");
} */

static inline void
lgdt (lgdt_t *p)
{
  asm volatile ("lgdt %0" : : "m" (*p));
}

static inline void
sgdt (lgdt_t *p)
{
  asm volatile ("sgdt %0" : "=m"(*p) : : "memory");
}


/*
 * gdt :
 *
 *1 000: NULL
 *2 008: VCPI reserved
 *3 010: VCPI reserved
 *4 018: VCPI reserved
 *5 020: 16 bit code (L64K, R+, C-)
 *6 028: 16 bit data (64K, W+)
 *7 030: 16 bit stub (255, W+)
 *8 038: 32 bit kernel data (4G, W+, B+)
 *9 040: 32 bit kernel code (4G, R+, C-)
 *A 048: temp TSS
 *B 050:
 *C 058:
 *D 060:
 *E 068:
 *F 070:
 */
descriptor_t *_gdt;
gate_t *_idt;

systable_t gdt_table;
systable_t idt_table;

static descriptor_t gdt[MAX_GDT_DESC];
static gate_t idt[MAX_GDT_DESC];


/*
 * [23/09/97] la gdt e la idt vengono ora allocate in modo statico
 */
void systab_setup()
{
	lgdt_t gdti;
        lidt_t idti;

        DEBUG_TRACE;

        _gdt = &gdt[0];
        memset(_gdt, 0, MAX_GDT_DESC*sizeof(descriptor_t));


        // imposta la nuova gdt
        sgdt(&gdti);
        memcpy(_gdt, (void*) gdti.address, gdti.limit + 1);
        gdti.limit = (sizeof(*_gdt) * MAX_GDT_DESC) - 1;
        gdti.address = _gdt;
        lgdt(&gdti);


        // imposta nuova idt
        _idt = &idt[0];
        idti.limit = (sizeof(*_idt) * MAX_IDT_DESC) - 1;
        idti.address = _idt;
        lidt(&idti);

        gdt_table.table = _gdt;
        gdt_table.alloc_start = GDT_ALLOC_START;
        gdt_table.alloc_end = MAX_GDT_DESC - 1;

        idt_table.table = (descriptor_t*)_idt;
        idt_table.alloc_start = 0;
        idt_table.alloc_end = MAX_IDT_DESC - 1;
        DEBUG_VERBOSE("gdt %xh idt %xh\n", gdti.address, idti.address);
}

int alloc_descriptors(systable_t *t, int num)
{

        int nn = num;
        int i;

        for (i = t->alloc_start; i <= t->alloc_end; i++) {
                if (IS_NULL_DESCRIPTOR(t->table[i])) {
                        if (--nn == 0) {
                                int j;
                                for (j = 0; j < num; j++) {
                                        MARK_USED_DESCRIPTOR(t->table[i-j]);
                                }
                                return i - j;
                        }
                } else nn = num;
        }
        return ENOMEM;

}

int alloc_descriptor(systable_t *t)
{
        int i;

        for (i = t->alloc_start; i <= t->alloc_end; i++) {
                if (IS_NULL_DESCRIPTOR(t->table[i])) {
                        MARK_USED_DESCRIPTOR(t->table[i]);
                        return i;

                };
        }
        return ENOMEM;
}

int free_descriptors(systable_t *t, int num, int count)
{
        int i;

        if (num+count > t->alloc_end) return EINVAL;

        for (i = 0; i < count; i++) {
                MARK_FREE_DESCRIPTOR(t->table[num+i]);
        }
        return 0;
}

int set_descriptor(systable_t *t, int numd, descriptor_t* d)
{
	if (numd < t->alloc_end && d) t->table[numd] = *d;
        else return EINVAL;
        return 0;

}

int get_descriptor(systable_t *t, int numd, descriptor_t* d)
{
	if (numd < t->alloc_end && d) *d = t->table[numd];
        else return EINVAL;
        return 0;
}