cos2000v2/lib/gdt.c

238 lines
7.7 KiB
C

/*******************************************************************************/
/* COS2000 - Compatible Operating System - LGPL v3 - Hordé Nicolas */
/* */
#include "gdt.h"
#include "asm.h"
#include "types.h"
#include "memory.h"
/* registre gdt */
static struct gdtr gdtreg;
/* table de GDT */
static gdtdes gdt[GDT_SIZE];
/* TSS */
static struct tss tss0;
/*******************************************************************************/
/* Créé un descripteur GDT */
void makegdtdes(u32 base, u32 limite, u8 acces, u8 flags, gdtdes * desc)
{
desc->lim0_15 = (limite & 0xffff);
desc->base0_15 = (base & 0xffff);
desc->base16_23 = (base & 0xff0000) >> 16;
desc->acces = acces;
desc->lim16_19 = (limite & 0xf0000) >> 16;
desc->flags = (flags & 0xf);
desc->base24_31 = (base & 0xff000000) >> 24;
return;
}
/*******************************************************************************/
/* Initialise la GDT */
void initgdt(u32 offset)
{
makegdtdes(0x0, 0x00000, 0x00, 0x00, &gdt[0]); /* descripteur nul */
makegdtdes(0x0, 0xFFFFF, SEG_PRESENT | SEG_NORMAL | SEG_CODE | SEG_RING0 | SEG_READ | SEG_ACCESSED, GRANULARITY_4K | OPSIZE_32B | SYS_AVAILABLE, &gdt[1]); /* code -> SEL_KERNEL_CODE */
makegdtdes(0x0, 0x00000, SEG_PRESENT | SEG_NORMAL | SEG_DATA | SEG_RING0 | SEG_EXPAND_DOWN | SEG_READ_WRITE | SEG_ACCESSED, GRANULARITY_4K | OPSIZE_32B | SYS_AVAILABLE, &gdt[2]); /* pile -> SEL_KERNEL_STACK */
makegdtdes(0x0, 0xFFFFF, SEG_PRESENT | SEG_NORMAL | SEG_CODE | SEG_RING3 | SEG_CONFORMING | SEG_READ | SEG_ACCESSED, GRANULARITY_4K | OPSIZE_32B | SYS_AVAILABLE, &gdt[3]); /* code -> SEL_USER_CODE */
makegdtdes(0x0, 0x00000, SEG_PRESENT | SEG_NORMAL | SEG_DATA | SEG_RING3 | SEG_EXPAND_DOWN | SEG_READ_WRITE | SEG_ACCESSED, GRANULARITY_4K | OPSIZE_32B | SYS_AVAILABLE, &gdt[4]); /* pile -> SEL_USER_STACK */
makegdtdes(0x0, 0xFFFFF, SEG_PRESENT | SEG_NORMAL | SEG_DATA | SEG_RING0 | SEG_READ_WRITE | SEG_ACCESSED, GRANULARITY_4K | OPSIZE_32B | SYS_AVAILABLE, &gdt[5]); /* data -> SEL_KERNEL_DATA */
makegdtdes(0x0, 0xFFFFF, SEG_PRESENT | SEG_NORMAL | SEG_DATA | SEG_RING3 | SEG_READ_WRITE | SEG_ACCESSED, GRANULARITY_4K | OPSIZE_32B | SYS_AVAILABLE, &gdt[6]); /* data -> SEL_USER_DATA */
tss0.trapflag = 0x00;
tss0.iomap = 0x00;
tss0.esp0 = 0x6000;
tss0.ss0 = SEL_TSS;
makegdtdes(&tss0, 0x67, SEG_PRESENT | SEG_CODE | SEG_RING3 | SEG_ACCESSED, 0x00, &gdt[7]); /* descripteur de tss */
/* initialise le registre gdt */
gdtreg.limite = GDT_SIZE * sizeof(gdtdes);
gdtreg.base = GDT_ADDR;
/* recopie de la GDT a son adresse */
memcpy(&gdt, (u8 *) gdtreg.base, gdtreg.limite, 1);
/* chargement du registre GDT */
lgdt(gdtreg);
/* initialisation des segments */
initselectors(offset);
}
/*******************************************************************************/
/* Initialise les selecteurs avec la GDT */
void initselectors(u32 executingoffset)
{
asm(" movw %[data], %%ax \n \
movw %%ax, %%ds \n \
movw %%ax, %%es \n \
movw %%ax, %%fs \n \
movw %%ax, %%gs \n \
movl %[offset], %%ebx \n \
movw %[stack], %%ax \n \
movw %%ax, %%ss \n \
movl %[stackoff], %%esp \n \
xor %%eax,%%eax\n\
xor %%ebx,%%ebx\n\
xor %%ecx,%%ecx\n\
xor %%edx,%%edx\n\
xor %%esi,%%esi\n\
xor %%edi,%%edi\n\
xor %%ebp,%%ebp\n\
jmp %%ebx"::[data] "i"(SEL_KERNEL_DATA),[code] "i"(SEL_KERNEL_CODE),[stack] "i"(SEL_KERNEL_STACK),[stackoff] "i"(KERNEL_STACK_ADDR),[offset] "m"(executingoffset));
}
/*******************************************************************************/
/* Change le TSS courant */
void setTSS(u32 ss, u32 sp)
{
tss0.trapflag = 0x00;
tss0.iomap = 0x00;
tss0.ss0 = SEL_TSS;
tss0.esp0 = sp;
tss0.ss0 = ss;
}
/*******************************************************************************/
/* Initialise le registre de tâche (TSR) */
void inittr(void)
{
ltr(SEL_TSS);
}
/*******************************************************************************/
/* récupère la base d'un descripteur GDT */
u32 getdesbase(u16 sel)
{
gdtdes *entry = GDT_ADDR;
u8 index = sel / sizeof(gdtdes);
return (entry[index].base0_15 + (entry[index].base16_23 << 16) +
(entry[index].base24_31 << 24));
}
/*******************************************************************************/
/* récupère la limite d'un descripteur GDT */
u32 getdeslimit(u16 sel)
{
gdtdes *entry = GDT_ADDR;
u8 index = sel / sizeof(gdtdes);
return (entry[index].lim0_15 + (entry[index].lim16_19 << 16));
}
/*******************************************************************************/
/* récupère la limite d'un descripteur GDT */
u32 getdesdpl(u16 sel)
{
gdtdes *entry = GDT_ADDR;
u8 index = sel / sizeof(gdtdes);
return (entry[index].acces >> 5 & 0x03);
}
/*******************************************************************************/
/* récupère le type d'un descripteur GDT */
u8 getdestype(u16 sel)
{
gdtdes *entry = GDT_ADDR;
u8 index = sel / sizeof(gdtdes);
if (((entry[index].acces & 0x14) == 0)
&& ((entry[index].acces & 0x08) > 0)
&& ((entry[index].acces & 0x01) > 0)
&& ((entry[index].flags & 0x06) == 0))
return 'T';
else
return (((entry[index].acces & 0x08) > 0) ? 'C' : 'D');
}
/*******************************************************************************/
/* récupère l'info 1 d'un descripteur GDT */
u8 getdesbit1(u16 sel)
{
gdtdes *entry = GDT_ADDR;
u8 index = sel / sizeof(gdtdes);
if (((entry[index].acces & 0x14) == 0)
&& ((entry[index].acces & 0x08) > 0)
&& ((entry[index].acces & 0x01) > 0)
&& ((entry[index].flags & 0x06) == 0))
return (((entry[index].acces & 0x04) > 0) ? 'B' : '-');
else
return (((entry[index].acces & 0x01) > 0) ? 'A' : '-');
}
/*******************************************************************************/
/* récupère l'info 2 d'un descripteur GDT */
u8 getdesbit2(u16 sel)
{
gdtdes *entry = GDT_ADDR;
u8 index = sel / sizeof(gdtdes);
if (((entry[index].acces & 0x20) == 0)
&& ((entry[index].acces & 0x08) > 0)
&& ((entry[index].acces & 0x01) > 0)
&& ((entry[index].flags & 0x06) == 0))
return (((entry[index].flags & 0x01) > 0) ? 'U' : '-');
else if ((entry[index].acces & 0x8) > 0)
return (((entry[index].acces & 0x02) > 0) ? 'R' : '-');
else
return (((entry[index].acces & 0x02) > 0) ? 'W' : 'R');
}
/*******************************************************************************/
/* récupère l'info 3 d'un descripteur GDT */
u8 getdesbit3(u16 sel)
{
gdtdes *entry = GDT_ADDR;
u8 index = sel / sizeof(gdtdes);
if ((entry[index].acces & 0x08) > 0)
return (((entry[index].acces & 0x04) > 0) ? 'C' : '-');
else
return (((entry[index].acces & 0x04) > 0) ? 'D' : 'U');
}
/*******************************************************************************/
/* récupère l'alignement d'un descripteur GDT */
u16 getdesalign(u16 sel)
{
gdtdes *entry = GDT_ADDR;
u8 index = sel / sizeof(gdtdes);
return (((entry[index].flags & 0x08) > 0) ? 4096 : 1);
}
/*******************************************************************************/
/* récupère si descripteur GDT est valide */
bool isdesvalid(u16 sel)
{
gdtdes *entry = GDT_ADDR;
u8 index = sel / sizeof(gdtdes);
return ((entry[index].acces & 0x80) > 0);
}
/*******************************************************************************/
/* récupère la dimension d'un descripteur GDT */
u32 getdessize(u16 sel)
{
gdtdes *entry = GDT_ADDR;
u8 index = sel / sizeof(gdtdes);
if (((entry[index].acces & 0x14) == 0)
&& ((entry[index].acces & 0x08) > 0)
&& ((entry[index].acces & 0x01) > 0)
&& ((entry[index].flags & 0x06) == 0))
return 32;
else
return (((entry[index].flags & 0x08) > 0) ? 32 : 16);
}