Merge branch 'khorben/tss'
This commit is contained in:
commit
96eafeac45
|
@ -23,14 +23,65 @@ typedef struct _GDTTable
|
|||
unsigned int prot;
|
||||
} GDTTable;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct _TSS
|
||||
{
|
||||
uint16_t link;
|
||||
uint16_t __padding0;
|
||||
uint32_t esp0;
|
||||
uint16_t ss0;
|
||||
uint16_t __padding1;
|
||||
uint32_t esp1;
|
||||
uint16_t ss1;
|
||||
uint16_t __padding2;
|
||||
uint32_t esp2;
|
||||
uint16_t ss2;
|
||||
uint16_t __padding3;
|
||||
uint32_t cr3;
|
||||
uint32_t eip;
|
||||
uint32_t eflags;
|
||||
uint32_t eax;
|
||||
uint32_t ecx;
|
||||
uint32_t edx;
|
||||
uint32_t ebx;
|
||||
uint32_t esp;
|
||||
uint32_t ebp;
|
||||
uint32_t esi;
|
||||
uint32_t edi;
|
||||
uint16_t es;
|
||||
uint16_t __padding4;
|
||||
uint16_t cs;
|
||||
uint16_t __padding5;
|
||||
uint16_t ss;
|
||||
uint16_t __padding6;
|
||||
uint16_t ds;
|
||||
uint16_t __padding7;
|
||||
uint16_t fs;
|
||||
uint16_t __padding8;
|
||||
uint16_t gs;
|
||||
uint16_t __padding9;
|
||||
uint16_t ldtr;
|
||||
uint16_t __padding10;
|
||||
uint16_t __padding11;
|
||||
uint16_t iopb;
|
||||
uint32_t ssp;
|
||||
} TSS;
|
||||
#pragma pack()
|
||||
|
||||
|
||||
/* constants */
|
||||
# define GDT_SYSTEM_TYPE_LDT 0x2
|
||||
# define GDT_SYSTEM_TYPE_TSS 0x9
|
||||
|
||||
|
||||
/* prototypes */
|
||||
GDT * gdt_init(void);
|
||||
int gdt_init_table(GDTTable const * table, size_t count);
|
||||
int gdt_init_table(GDTTable const * table, size_t table_cnt, size_t tss_cnt);
|
||||
|
||||
|
||||
/* useful */
|
||||
int gdt_append(GDT * gdt, vaddr_t base, size_t size, unsigned int prot);
|
||||
int gdt_append_system(GDT * gdt, void * base, size_t size, unsigned int type);
|
||||
|
||||
void gdt_apply(GDT * gdt);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2018-2019 Pierre Pronchery <khorben@defora.org> */
|
||||
/* Copyright (c) 2018-2025 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS uKernel */
|
||||
|
||||
|
||||
|
@ -92,7 +92,7 @@ int multiboot(const ukMultibootInfo * mi)
|
|||
if(_arch_setgdt64(_gdt_4gb, sizeof(_gdt_4gb) / sizeof(*_gdt_4gb)) != 0)
|
||||
#else
|
||||
if(gdt_init_table((const GDTTable *)&_gdt_4gb,
|
||||
sizeof(_gdt_4gb) / sizeof(*_gdt_4gb)) != 0)
|
||||
sizeof(_gdt_4gb) / sizeof(*_gdt_4gb), 1) != 0)
|
||||
#endif
|
||||
{
|
||||
puts("Could not setup the GDT");
|
||||
|
|
143
src/loader/gdt.c
143
src/loader/gdt.c
|
@ -19,8 +19,8 @@
|
|||
|
||||
/* access */
|
||||
# define GDT_ACCESS_SET 0x01
|
||||
# define GDT_ACCESS_RW 0x02
|
||||
# define GDT_ACCESS_X 0x08
|
||||
# define GDT_ACCESS_PROT_RW 0x02
|
||||
# define GDT_ACCESS_PROT_X 0x08
|
||||
# define GDT_ACCESS_SEGMENT 0x10
|
||||
# define GDT_ACCESS_RING(level) ((level) << 5)
|
||||
# define GDT_ACCESS_PRESENT 0x80
|
||||
|
@ -48,6 +48,21 @@ typedef struct _GDTEntry
|
|||
} GDTEntry;
|
||||
#pragma pack()
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct _LDT
|
||||
{
|
||||
uint8_t limit0;
|
||||
uint8_t limit1;
|
||||
uint8_t base0;
|
||||
uint8_t base1;
|
||||
uint8_t base2;
|
||||
uint8_t access;
|
||||
unsigned int limit2:4;
|
||||
unsigned int flags:4;
|
||||
uint8_t base3;
|
||||
} LDT;
|
||||
#pragma pack()
|
||||
|
||||
struct _GDT
|
||||
{
|
||||
GDTEntry entries[GDT_ENTRIES_MAX];
|
||||
|
@ -58,9 +73,13 @@ struct _GDT
|
|||
/* prototypes */
|
||||
extern void __arch_setgdt(GDTEntry const * entries, size_t count);
|
||||
|
||||
static int _gdt_append_entry(GDT * gdt, vaddr_t base, uint32_t limit,
|
||||
uint8_t access, uint8_t flags);
|
||||
|
||||
|
||||
/* variables */
|
||||
static GDT _gdt;
|
||||
static TSS _tss;
|
||||
|
||||
|
||||
/* functions */
|
||||
|
@ -74,17 +93,27 @@ GDT * gdt_init(void)
|
|||
|
||||
|
||||
/* gdt_init_table */
|
||||
int gdt_init_table(GDTTable const * table, size_t count)
|
||||
int gdt_init_table(GDTTable const * table, size_t table_cnt, size_t tss_cnt)
|
||||
{
|
||||
int ret = 0;
|
||||
GDT * gdt;
|
||||
size_t i;
|
||||
|
||||
gdt = gdt_init();
|
||||
for(i = 0; i < count; i++)
|
||||
for(i = 0; i < table_cnt; i++)
|
||||
if((ret = gdt_append(gdt, table[i].base, table[i].size,
|
||||
table[i].prot)) != 0)
|
||||
return ret;
|
||||
/* set the TSS */
|
||||
if(tss_cnt > 1)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
else if(tss_cnt == 1 && (ret = gdt_append_system(gdt, &_tss,
|
||||
sizeof(_tss), GDT_SYSTEM_TYPE_TSS))
|
||||
!= 0)
|
||||
return ret;
|
||||
gdt_apply(gdt);
|
||||
return 0;
|
||||
}
|
||||
|
@ -94,10 +123,9 @@ int gdt_init_table(GDTTable const * table, size_t count)
|
|||
/* gdt_append */
|
||||
int gdt_append(GDT * gdt, vaddr_t base, size_t size, unsigned int prot)
|
||||
{
|
||||
GDTEntry * entry;
|
||||
uint32_t limit;
|
||||
uint8_t access = GDT_ACCESS_PRESENT
|
||||
| GDT_ACCESS_SEGMENT | GDT_ACCESS_RING(0);
|
||||
uint8_t access = GDT_ACCESS_SEGMENT | GDT_ACCESS_PRESENT
|
||||
| GDT_ACCESS_RING(0);
|
||||
uint8_t flags = GDT_FLAG_PROTECTED_MODE;
|
||||
|
||||
/* check for errors */
|
||||
|
@ -106,9 +134,7 @@ int gdt_append(GDT * gdt, vaddr_t base, size_t size, unsigned int prot)
|
|||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
if(gdt->entries_cnt >= sizeof(gdt->entries) / sizeof(*gdt->entries)
|
||||
|| size > ULONG_MAX
|
||||
|| ULONG_MAX - size < base)
|
||||
if(size > ULONG_MAX || ULONG_MAX - size < base)
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
|
@ -120,41 +146,72 @@ int gdt_append(GDT * gdt, vaddr_t base, size_t size, unsigned int prot)
|
|||
errno = EPERM;
|
||||
return -1;
|
||||
}
|
||||
entry = &gdt->entries[gdt->entries_cnt];
|
||||
/* base */
|
||||
entry->base0 = base & 0xff;
|
||||
entry->base1 = (base & 0xff00) >> 8;
|
||||
entry->base2 = (base & 0xff0000) >> 16;
|
||||
entry->base3 = (base & 0xff000000) >> 24;
|
||||
/* limit */
|
||||
if(size - 1 > GDT_LIMIT_MAX)
|
||||
{
|
||||
limit = (size & 0xfff) == 0
|
||||
? (size >> 12)
|
||||
: (((size | 0xfff) + 1) >> 12);
|
||||
limit--;
|
||||
? (size >> 12) - 1
|
||||
: (((size | 0xfff) + 1) >> 12) - 1;
|
||||
flags |= GDT_FLAG_PAGE_GRANULARITY;
|
||||
}
|
||||
else
|
||||
limit = size - 1;
|
||||
entry->limit0 = limit & 0xff;
|
||||
entry->limit1 = (limit & 0xff00) >> 8;
|
||||
entry->limit2 = (limit & 0xf0000) >> 16;
|
||||
/* access */
|
||||
if(prot == (PROT_READ | PROT_EXEC))
|
||||
/* code segment */
|
||||
access |= GDT_ACCESS_RW | GDT_ACCESS_X;
|
||||
access |= GDT_ACCESS_PROT_RW | GDT_ACCESS_PROT_X;
|
||||
else if(prot == (PROT_READ | PROT_WRITE))
|
||||
/* data segment (read/write) */
|
||||
access |= GDT_ACCESS_RW;
|
||||
access |= GDT_ACCESS_PROT_RW;
|
||||
else if(prot == PROT_READ)
|
||||
/* data segment (read-only) */
|
||||
access |= GDT_ACCESS_SET;
|
||||
entry->access = access;
|
||||
/* flags */
|
||||
entry->flags = flags;
|
||||
gdt->entries_cnt++;
|
||||
return 0;
|
||||
return _gdt_append_entry(gdt, base, limit, access, flags);
|
||||
}
|
||||
|
||||
|
||||
/* gdt_append_system */
|
||||
static int _append_system_ldt(GDT * gdt, void * base, size_t size);
|
||||
static int _append_system_tss(GDT * gdt, void * base, size_t size);
|
||||
|
||||
int gdt_append_system(GDT * gdt, void * base, size_t size, unsigned int type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case GDT_SYSTEM_TYPE_LDT:
|
||||
return _append_system_ldt(gdt, base, size);
|
||||
case GDT_SYSTEM_TYPE_TSS:
|
||||
return _append_system_tss(gdt, base, size);
|
||||
default:
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int _append_system_ldt(GDT * gdt, void * base, size_t size)
|
||||
{
|
||||
uint32_t access = GDT_ACCESS_PRESENT | GDT_SYSTEM_TYPE_LDT;
|
||||
uint8_t flags = GDT_FLAG_PROTECTED_MODE;
|
||||
|
||||
if(size != sizeof(LDT))
|
||||
{
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
return _gdt_append_entry(gdt, (vaddr_t)base, size - 1, access, flags);
|
||||
}
|
||||
|
||||
static int _append_system_tss(GDT * gdt, void * base, size_t size)
|
||||
{
|
||||
uint32_t access = GDT_ACCESS_PRESENT | GDT_SYSTEM_TYPE_TSS;
|
||||
uint8_t flags = GDT_FLAG_PROTECTED_MODE;
|
||||
|
||||
if(size != sizeof(TSS))
|
||||
{
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
return _gdt_append_entry(gdt, (vaddr_t)base, size - 1, access, flags);
|
||||
}
|
||||
|
||||
|
||||
|
@ -163,4 +220,32 @@ void gdt_apply(GDT * gdt)
|
|||
{
|
||||
__arch_setgdt(gdt->entries, gdt->entries_cnt);
|
||||
}
|
||||
|
||||
|
||||
/* private */
|
||||
/* gdt_append_entry */
|
||||
static int _gdt_append_entry(GDT * gdt, vaddr_t base, uint32_t limit,
|
||||
uint8_t access, uint8_t flags)
|
||||
{
|
||||
GDTEntry * entry;
|
||||
|
||||
/* check for errors */
|
||||
if(gdt->entries_cnt >= sizeof(gdt->entries) / sizeof(*gdt->entries))
|
||||
{
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
entry = &gdt->entries[gdt->entries_cnt];
|
||||
entry->base0 = base & 0xff;
|
||||
entry->base1 = (base & 0xff00) >> 8;
|
||||
entry->base2 = (base & 0xff0000) >> 16;
|
||||
entry->base3 = (base & 0xff000000) >> 24;
|
||||
entry->limit0 = limit & 0xff;
|
||||
entry->limit1 = (limit & 0xff00) >> 8;
|
||||
entry->limit2 = (limit & 0xf0000) >> 16;
|
||||
entry->access = access;
|
||||
entry->flags = flags;
|
||||
gdt->entries_cnt++;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* $Id$ */
|
||||
/* Copyright (c) 2018-2020 Pierre Pronchery <khorben@defora.org> */
|
||||
/* Copyright (c) 2018-2025 Pierre Pronchery <khorben@defora.org> */
|
||||
/* This file is part of DeforaOS uKernel */
|
||||
|
||||
|
||||
|
@ -87,7 +87,7 @@ int multiboot(const ukMultibootInfo * mi)
|
|||
|
||||
/* setup the GDT */
|
||||
if(gdt_init_table((const GDTTable *)&_gdt_4gb,
|
||||
sizeof(_gdt_4gb) / sizeof(*_gdt_4gb)) != 0)
|
||||
sizeof(_gdt_4gb) / sizeof(*_gdt_4gb), 1) != 0)
|
||||
{
|
||||
puts("Could not setup the GDT");
|
||||
return 4;
|
||||
|
|
|
@ -12,6 +12,11 @@
|
|||
|
||||
|
||||
#if defined(__amd64__) || defined(__i386__)
|
||||
/* variables */
|
||||
static TSS tss;
|
||||
|
||||
|
||||
/* functions */
|
||||
/* __arch_setgdt */
|
||||
void __arch_setgdt(GDTEntry const * entries, size_t count)
|
||||
{
|
||||
|
@ -51,6 +56,7 @@ int main(int argc, char * argv[])
|
|||
gdt = gdt_init();
|
||||
gdt_append(gdt, 0x00000000, 0xffffffff, PROT_READ | PROT_EXEC);
|
||||
gdt_append(gdt, 0x00000000, 0xffffffff, PROT_READ | PROT_WRITE);
|
||||
gdt_append_system(gdt, &tss, sizeof(tss), GDT_SYSTEM_TYPE_TSS);
|
||||
gdt_apply(gdt);
|
||||
|
||||
/* 4 MB code + 4 MB data (read-write) + 4 MB data (read-only) */
|
||||
|
@ -59,6 +65,7 @@ int main(int argc, char * argv[])
|
|||
gdt_append(gdt, 0x00400000, 0x00400000, PROT_READ | PROT_EXEC);
|
||||
gdt_append(gdt, 0x00800000, 0x00400000, PROT_READ | PROT_WRITE);
|
||||
gdt_append(gdt, 0x00c00000, 0x00400000, PROT_READ);
|
||||
gdt_append_system(gdt, &tss, sizeof(tss), GDT_SYSTEM_TYPE_TSS);
|
||||
gdt_apply(gdt);
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue
Block a user