Skip to content

Commit 084bdd1

Browse files
committed
Merge branch 'khorben/gdt'
2 parents 6aec0c1 + fb07c0b commit 084bdd1

File tree

10 files changed

+269
-100
lines changed

10 files changed

+269
-100
lines changed

src/arch/amd64/gdt.S

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,36 @@
99
.section .text
1010
/* arch_setgdt */
1111
.global __arch_setgdt
12+
#ifndef __clang__
1213
.type __arch_setgdt, @function
14+
#endif
1315
__arch_setgdt:
14-
#if 0
1516
lea gdt_descriptor, %rcx
16-
#else
17-
mov (gdt_descriptor), %rcx
18-
#endif
17+
1918
/* set the offset of the GDT */
2019
mov %rsi, 0x2(%rcx)
20+
2121
/* set the size of the GDT */
22+
shl $0x3, %rdi
2223
dec %rdi
2324
mov %di, (%rcx)
25+
2426
/* load the GDT */
2527
lgdt (%rcx)
28+
29+
push $0x8
30+
lea gdt_flush, %rax
31+
push %rax
32+
retf
33+
34+
gdt_flush:
35+
mov $0x10, %ax
36+
mov %ax, %ds
37+
mov %ax, %es
38+
mov %ax, %fs
39+
mov %ax, %gs
40+
mov %ax, %ss
41+
2642
ret
2743

2844

@@ -31,4 +47,4 @@ __arch_setgdt:
3147
.align 16
3248
gdt_descriptor:
3349
.skip 2 /* size */
34-
.skip 4 /* offset */
50+
.skip 8 /* offset */

src/arch/i386/gdt.S

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,29 @@
1414
#endif
1515
__arch_setgdt:
1616
lea gdt_descriptor, %ecx
17+
1718
/* set the offset of the GDT */
1819
mov 0x4(%esp), %eax
1920
mov %eax, 0x2(%ecx)
21+
2022
/* set the size of the GDT */
2123
mov 0x8(%esp), %eax
24+
shl $0x3, %eax
2225
dec %eax
2326
mov %ax, (%ecx)
2427
/* load the GDT */
25-
lgdt (%ecx)
28+
lgdt (gdt_descriptor)
29+
30+
/* apply the GDT */
31+
mov $0x10, %ax
32+
mov %ax, %ds
33+
mov %ax, %es
34+
mov %ax, %fs
35+
mov %ax, %gs
36+
mov %ax, %ss
37+
ljmp $0x08, $gdt_flush
38+
gdt_flush:
39+
2640
ret
2741

2842

src/arch/i386/gdt.h

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,37 @@
11
/* $Id$ */
2-
/* Copyright (c) 2018 Pierre Pronchery <[email protected]> */
2+
/* Copyright (c) 2018-2025 Pierre Pronchery <[email protected]> */
33
/* This file is part of DeforaOS uKernel */
44

55

66

77
#ifndef UKERNEL_ARCH_I386_GDT_H
88
# define UKERNEL_ARCH_I386_GDT_H
99

10+
# include <sys/mman.h>
1011
# include <sys/types.h>
1112
# include <stdint.h>
1213

1314

1415
/* public */
1516
/* types */
16-
typedef struct _GDT
17+
typedef struct _GDT GDT;
18+
19+
typedef struct _GDTTable
1720
{
1821
vaddr_t base;
19-
vaddr_t limit;
20-
uint8_t type;
21-
} GDT;
22+
size_t size;
23+
unsigned int prot;
24+
} GDTTable;
2225

2326

2427
/* prototypes */
25-
int _arch_setgdt(GDT const * gdt, size_t count);
28+
GDT * gdt_init(void);
29+
int gdt_init_table(GDTTable const * table, size_t count);
30+
31+
32+
/* useful */
33+
int gdt_append(GDT * gdt, vaddr_t base, size_t size, unsigned int prot);
34+
35+
void gdt_apply(GDT * gdt);
2636

2737
#endif /* !UKERNEL_ARCH_I386_GDT_H */

src/drivers/boot/multiboot.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@
1111
# include <stdio.h>
1212
# include <string.h>
1313
# include <elf.h>
14-
# include "arch/amd64/gdt.h"
15-
# include "arch/i386/gdt.h"
1614
# include "drivers/boot/multiboot.h"
1715

1816
# ifndef MAX

src/kernel/multiboot.c

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,10 @@
2727
/* private */
2828
/* constants */
2929
/* GDT: 4GB flat memory setup */
30-
static const GDT _gdt_4gb[4] =
30+
static const GDTTable _gdt_4gb[2] =
3131
{
32-
{ 0x00000000, 0x00000000, 0x00 },
33-
{ 0x00000000, 0xffffffff, 0x9a },
34-
{ 0x00000000, 0xffffffff, 0x92 },
35-
{ 0x00000000, 0x00000000, 0x89 }
32+
{ 0x00000000, 0xffffffff, PROT_READ | PROT_EXEC },
33+
{ 0x00000000, 0xffffffff, PROT_READ | PROT_WRITE }
3634
};
3735

3836
static const IDT _idt[] =
@@ -93,7 +91,8 @@ int multiboot(const ukMultibootInfo * mi)
9391
#if defined(__amd64__)
9492
if(_arch_setgdt64(_gdt_4gb, sizeof(_gdt_4gb) / sizeof(*_gdt_4gb)) != 0)
9593
#else
96-
if(_arch_setgdt(_gdt_4gb, sizeof(_gdt_4gb) / sizeof(*_gdt_4gb)) != 0)
94+
if(gdt_init_table((const GDTTable *)&_gdt_4gb,
95+
sizeof(_gdt_4gb) / sizeof(*_gdt_4gb)) != 0)
9796
#endif
9897
{
9998
puts("Could not setup the GDT");

src/loader/gdt.c

Lines changed: 126 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,166 @@
11
/* $Id$ */
2-
/* Copyright (c) 2018 Pierre Pronchery <[email protected]> */
2+
/* Copyright (c) 2018-2025 Pierre Pronchery <[email protected]> */
33
/* This file is part of DeforaOS uKernel */
44

55

66

77
#if defined(__amd64__) || defined(__i386__)
8+
# include <limits.h>
89
# include <stdint.h>
910
# include <string.h>
1011
# include <errno.h>
1112
# include "arch/amd64/gdt.h"
1213
# include "arch/i386/gdt.h"
1314

1415

16+
/* constants */
17+
# define GDT_ENTRIES_MAX 8192
18+
# define GDT_LIMIT_MAX 0x000fffff
19+
20+
/* access */
21+
# define GDT_ACCESS_SET 0x01
22+
# define GDT_ACCESS_RW 0x02
23+
# define GDT_ACCESS_X 0x08
24+
# define GDT_ACCESS_SEGMENT 0x10
25+
# define GDT_ACCESS_RING(level) ((level) << 5)
26+
# define GDT_ACCESS_PRESENT 0x80
27+
28+
/* flags */
29+
# define GDT_FLAG_LONG_MODE 0x2 /* 64-bit code segment */
30+
# define GDT_FLAG_PROTECTED_MODE 0x4 /* 32-bit protected mode
31+
code segment */
32+
# define GDT_FLAG_PAGE_GRANULARITY 0x8 /* 4 KB page size */
33+
34+
35+
/* types */
36+
#pragma pack(1)
37+
typedef struct _GDTEntry
38+
{
39+
uint8_t limit0;
40+
uint8_t limit1;
41+
uint8_t base0;
42+
uint8_t base1;
43+
uint8_t base2;
44+
uint8_t access;
45+
unsigned int limit2:4;
46+
unsigned int flags:4;
47+
uint8_t base3;
48+
} GDTEntry;
49+
#pragma pack()
50+
51+
struct _GDT
52+
{
53+
GDTEntry entries[GDT_ENTRIES_MAX];
54+
size_t entries_cnt;
55+
};
56+
57+
1558
/* prototypes */
16-
extern void __arch_setgdt(uint8_t * buf, size_t count);
59+
extern void __arch_setgdt(GDTEntry const * entries, size_t count);
1760

1861

1962
/* variables */
20-
static uint8_t _buf[65536];
63+
static GDT _gdt;
2164

2265

2366
/* functions */
24-
/* arch_setgdt */
25-
int _arch_setgdt(GDT const * gdt, size_t count)
67+
/* gdt_init */
68+
GDT * gdt_init(void)
69+
{
70+
memset(&_gdt.entries[0], 0, sizeof(_gdt.entries[0]));
71+
_gdt.entries_cnt = 1;
72+
return &_gdt;
73+
}
74+
75+
76+
/* gdt_init_table */
77+
int gdt_init_table(GDTTable const * table, size_t count)
2678
{
27-
uint8_t * buf = _buf;
79+
int ret = 0;
80+
GDT * gdt;
2881
size_t i;
29-
GDT g;
3082

31-
memset(&_buf, 0, sizeof(_buf));
32-
/* check for errors */
33-
if(count == 0 || count > sizeof(_buf) / sizeof(*gdt))
34-
{
35-
errno = ERANGE;
36-
return -1;
37-
}
83+
gdt = gdt_init();
3884
for(i = 0; i < count; i++)
39-
{
40-
g = gdt[i];
41-
buf = &_buf[sizeof(g) * i];
42-
if(g.limit > 65536)
43-
{
44-
/* make sure the limit can be encoded */
45-
if((g.limit & 0xfff) != 0xfff)
46-
return -1;
47-
g.limit = g.limit >> 12;
48-
buf[6] = 0xc0;
49-
}
50-
else
51-
buf[6] = 0x40;
52-
//encode the limit
53-
buf[0] = g.limit & 0xff;
54-
buf[1] = (g.limit >> 8) & 0xff;
55-
buf[6] |= (g.limit >> 16) & 0xf;
56-
//encode the base
57-
buf[2] = g.base & 0xff;
58-
buf[3] = (g.base >> 8) & 0xff;
59-
buf[4] = (g.base >> 16) & 0xff;
60-
buf[7] = (g.base >> 24) & 0xff;
61-
//encode the type
62-
buf[5] = g.type;
63-
}
64-
__arch_setgdt(_buf, count);
85+
if((ret = gdt_append(gdt, table[i].base, table[i].size,
86+
table[i].prot)) != 0)
87+
return ret;
88+
gdt_apply(gdt);
6589
return 0;
6690
}
6791

6892

69-
/* arch_setgdt64 */
70-
int _arch_setgdt64(GDT const * gdt, size_t count)
93+
/* useful */
94+
/* gdt_append */
95+
int gdt_append(GDT * gdt, vaddr_t base, size_t size, unsigned int prot)
7196
{
72-
uint8_t * buf;
73-
size_t i;
74-
GDT g;
97+
GDTEntry * entry;
98+
uint32_t limit;
99+
uint8_t access = GDT_ACCESS_PRESENT
100+
| GDT_ACCESS_SEGMENT | GDT_ACCESS_RING(0);
101+
uint8_t flags = GDT_FLAG_PROTECTED_MODE;
75102

76-
memset(&_buf, 0, sizeof(_buf));
77103
/* check for errors */
78-
if(count == 0 || count > sizeof(_buf) / sizeof(*gdt))
104+
if(size == 0)
79105
{
80106
errno = ERANGE;
81107
return -1;
82108
}
83-
for(i = 0; i < count; i++)
109+
if(gdt->entries_cnt >= sizeof(gdt->entries) / sizeof(*gdt->entries)
110+
|| size > ULONG_MAX
111+
|| ULONG_MAX - size < base)
112+
{
113+
errno = ENOMEM;
114+
return -1;
115+
}
116+
if(prot != PROT_READ
117+
&& prot != (PROT_READ | PROT_WRITE)
118+
&& prot != (PROT_READ | PROT_EXEC))
119+
{
120+
errno = EPERM;
121+
return -1;
122+
}
123+
entry = &gdt->entries[gdt->entries_cnt];
124+
/* base */
125+
entry->base0 = base & 0xff;
126+
entry->base1 = (base & 0xff00) >> 8;
127+
entry->base2 = (base & 0xff0000) >> 16;
128+
entry->base3 = (base & 0xff000000) >> 24;
129+
/* limit */
130+
if(size - 1 > GDT_LIMIT_MAX)
84131
{
85-
g = gdt[i];
86-
buf = &_buf[sizeof(g) * i];
87-
if(g.limit > 65536)
88-
{
89-
/* make sure the limit can be encoded */
90-
if((g.limit & 0xfff) != 0xfff)
91-
return -1;
92-
g.limit = g.limit >> 12;
93-
buf[6] = 0xa0;
94-
}
95-
else
96-
buf[6] = 0x20;
97-
//encode the limit
98-
buf[0] = g.limit & 0xff;
99-
buf[1] = (g.limit >> 8) & 0xff;
100-
buf[6] |= (g.limit >> 16) & 0xf;
101-
//encode the base
102-
buf[2] = g.base & 0xff;
103-
buf[3] = (g.base >> 8) & 0xff;
104-
buf[4] = (g.base >> 16) & 0xff;
105-
buf[7] = (g.base >> 24) & 0xff;
106-
//encode the type
107-
buf[5] = g.type;
132+
limit = (size & 0xfff) == 0
133+
? (size >> 12)
134+
: (((size | 0xfff) + 1) >> 12);
135+
limit--;
136+
flags |= GDT_FLAG_PAGE_GRANULARITY;
108137
}
109-
__arch_setgdt(_buf, count);
138+
else
139+
limit = size - 1;
140+
entry->limit0 = limit & 0xff;
141+
entry->limit1 = (limit & 0xff00) >> 8;
142+
entry->limit2 = (limit & 0xf0000) >> 16;
143+
/* access */
144+
if(prot == (PROT_READ | PROT_EXEC))
145+
/* code segment */
146+
access |= GDT_ACCESS_RW | GDT_ACCESS_X;
147+
else if(prot == (PROT_READ | PROT_WRITE))
148+
/* data segment (read/write) */
149+
access |= GDT_ACCESS_RW;
150+
else if(prot == PROT_READ)
151+
/* data segment (read-only) */
152+
access |= GDT_ACCESS_SET;
153+
entry->access = access;
154+
/* flags */
155+
entry->flags = flags;
156+
gdt->entries_cnt++;
110157
return 0;
111158
}
159+
160+
161+
/* gdt_apply */
162+
void gdt_apply(GDT * gdt)
163+
{
164+
__arch_setgdt(gdt->entries, gdt->entries_cnt);
165+
}
112166
#endif

0 commit comments

Comments
 (0)