1/*
2 * Copyright 2002-2006, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
6 * Distributed under the terms of the NewOS License.
7 */
8#ifndef _KERNEL_ARCH_X86_32_DESCRIPTORS_H
9#define _KERNEL_ARCH_X86_32_DESCRIPTORS_H
10
11
12// Segments common for all CPUs.
13#define KERNEL_CODE_SEGMENT			1
14#define KERNEL_DATA_SEGMENT			2
15
16#define USER_CODE_SEGMENT			3
17#define USER_DATA_SEGMENT			4
18
19#define BOOT_GDT_SEGMENT_COUNT		(USER_DATA_SEGMENT + 2) // match x86_64
20
21#define APM_CODE32_SEGMENT			5
22#define APM_CODE16_SEGMENT			6
23#define APM_DATA_SEGMENT			7
24
25#define BIOS_DATA_SEGMENT			8
26
27// Per-CPU segments.
28#define TSS_SEGMENT					9
29#define DOUBLE_FAULT_TSS_SEGMENT	10
30#define KERNEL_TLS_SEGMENT			11
31#define USER_TLS_SEGMENT			12
32#define APM_SEGMENT					13
33
34#define GDT_SEGMENT_COUNT			14
35
36
37#define KERNEL_CODE_SELECTOR	((KERNEL_CODE_SEGMENT << 3) | DPL_KERNEL)
38#define KERNEL_DATA_SELECTOR	((KERNEL_DATA_SEGMENT << 3) | DPL_KERNEL)
39
40#define USER_CODE_SELECTOR	((USER_CODE_SEGMENT << 3) | DPL_USER)
41#define USER_DATA_SELECTOR	((USER_DATA_SEGMENT << 3) | DPL_USER)
42
43#define KERNEL_TLS_SELECTOR	((KERNEL_TLS_SEGMENT << 3) | DPL_KERNEL)
44
45
46#ifndef _ASSEMBLER
47	// this file can also be included from assembler as well
48	// (and is in arch_interrupts.S)
49
50// defines entries in the GDT/LDT
51
52struct segment_descriptor {
53	uint16 limit_00_15;				// bit	 0 - 15
54	uint16 base_00_15;				//		16 - 31
55	uint32 base_23_16 : 8;			//		 0 -  7
56	uint32 type : 4;				//		 8 - 11
57	uint32 desc_type : 1;			//		12		(0 = system, 1 = code/data)
58	uint32 privilege_level : 2;		//		13 - 14
59	uint32 present : 1;				//		15
60	uint32 limit_19_16 : 4;			//		16 - 19
61	uint32 available : 1;			//		20
62	uint32 zero : 1;				//		21
63	uint32 d_b : 1;					//		22
64	uint32 granularity : 1;			//		23
65	uint32 base_31_24 : 8;			//		24 - 31
66};
67
68struct interrupt_descriptor {
69	uint32 a;
70	uint32 b;
71};
72
73struct tss {
74	uint16 prev_task;
75	uint16 unused0;
76	uint32 sp0;
77	uint32 ss0;
78	uint32 sp1;
79	uint32 ss1;
80	uint32 sp2;
81	uint32 ss2;
82	uint32 cr3;
83	uint32 eip, eflags, eax, ecx, edx, ebx, esp, ebp, esi, edi;
84	uint32 es, cs, ss, ds, fs, gs;
85	uint32 ldt_seg_selector;
86	uint16 unused1;
87	uint16 io_map_base;
88};
89
90typedef segment_descriptor global_descriptor_table[GDT_SEGMENT_COUNT];
91extern global_descriptor_table gGDTs[];
92
93
94static inline void
95clear_segment_descriptor(segment_descriptor* desc)
96{
97	*(long long*)desc = 0;
98}
99
100
101static inline void
102set_segment_descriptor_base(segment_descriptor* desc, addr_t base)
103{
104	desc->base_00_15 = (addr_t)base & 0xffff;	// base is 32 bits long
105	desc->base_23_16 = ((addr_t)base >> 16) & 0xff;
106	desc->base_31_24 = ((addr_t)base >> 24) & 0xff;
107}
108
109
110static inline void
111set_segment_descriptor(segment_descriptor* desc, addr_t base, uint32 limit,
112	uint8 type, uint8 privilegeLevel)
113{
114	set_segment_descriptor_base(desc, base);
115
116	// limit is 20 bits long
117	if (limit & 0xfff00000) {
118		desc->limit_00_15 = ((addr_t)limit >> 12) & 0x0ffff;
119		desc->limit_19_16 = ((addr_t)limit >> 28) & 0xf;
120		desc->granularity = 1;	// 4 KB granularity
121	} else {
122		desc->limit_00_15 = (addr_t)limit & 0x0ffff;
123		desc->limit_19_16 = ((addr_t)limit >> 16) & 0xf;
124		desc->granularity = 0;	// 1 byte granularity
125	}
126
127	desc->type = type;
128	desc->desc_type = DT_CODE_DATA_SEGMENT;
129	desc->privilege_level = privilegeLevel;
130
131	desc->present = 1;
132	desc->available = 0;	// system available bit is currently not used
133	desc->d_b = 1;			// 32-bit code
134
135	desc->zero = 0;
136}
137
138
139static inline void
140set_tss_descriptor(segment_descriptor* desc, addr_t base, uint32 limit)
141{
142	// the TSS descriptor has a special layout different from the standard descriptor
143	set_segment_descriptor_base(desc, base);
144
145	desc->limit_00_15 = (addr_t)limit & 0x0ffff;
146	desc->limit_19_16 = 0;
147
148	desc->type = DT_TSS;
149	desc->desc_type = DT_SYSTEM_SEGMENT;
150	desc->privilege_level = DPL_KERNEL;
151
152	desc->present = 1;
153	desc->granularity = 0;	// 1 Byte granularity
154	desc->available = 0;	// system available bit is currently not used
155	desc->d_b = 0;
156
157	desc->zero = 0;
158}
159
160
161static inline segment_descriptor*
162get_gdt(int32 cpu)
163{
164	return gGDTs[cpu];
165}
166
167
168#endif	/* _ASSEMBLER */
169
170#endif	/* _KERNEL_ARCH_X86_32_DESCRIPTORS_H */
171