1/*
2 * Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
3 * Distributed under the terms of the MIT License.
4 */
5#ifndef _KERNEL_ARCH_X86_64_DESCRIPTORS_H
6#define _KERNEL_ARCH_X86_64_DESCRIPTORS_H
7
8
9// Segment definitions.
10// Note that the ordering of these is important to SYSCALL/SYSRET.
11#define KERNEL_CODE_SEGMENT		1
12#define KERNEL_DATA_SEGMENT		2
13#define USER32_CODE_SEGMENT		3
14#define USER_DATA_SEGMENT		4
15#define USER_CODE_SEGMENT		5
16
17#define BOOT_GDT_SEGMENT_COUNT	(USER_CODE_SEGMENT + 1)
18
19#define KERNEL_CODE_SELECTOR	((KERNEL_CODE_SEGMENT << 3) | DPL_KERNEL)
20#define KERNEL_DATA_SELECTOR	((KERNEL_DATA_SEGMENT << 3) | DPL_KERNEL)
21
22#define USER32_CODE_SELECTOR	((USER32_CODE_SEGMENT << 3) | DPL_USER)
23#define USER_CODE_SELECTOR		((USER_CODE_SEGMENT << 3) | DPL_USER)
24#define USER_DATA_SELECTOR		((USER_DATA_SEGMENT << 3) | DPL_USER)
25
26
27#ifndef _ASSEMBLER
28
29
30// Structure of a segment descriptor.
31struct segment_descriptor {
32	uint32 limit0 : 16;
33	uint32 base0 : 24;
34	uint32 type : 4;
35	uint32 desc_type : 1;
36	uint32 dpl : 2;
37	uint32 present : 1;
38	uint32 limit1 : 4;
39	uint32 available : 1;
40	uint32 long_mode : 1;
41	uint32 d_b : 1;
42	uint32 granularity : 1;
43	uint32 base1 : 8;
44} _PACKED;
45
46struct tss {
47	uint32 _reserved1;
48	uint64 sp0;
49	uint64 sp1;
50	uint64 sp2;
51	uint64 _reserved2;
52	uint64 ist1;
53	uint64 ist2;
54	uint64 ist3;
55	uint64 ist4;
56	uint64 ist5;
57	uint64 ist6;
58	uint64 ist7;
59	uint64 _reserved3;
60	uint16 _reserved4;
61	uint16 io_map_base;
62} _PACKED;
63
64
65static inline void
66clear_segment_descriptor(segment_descriptor* desc)
67{
68	*(uint64*)desc = 0;
69}
70
71
72static inline void
73set_segment_descriptor(segment_descriptor* desc, uint8 type, uint8 dpl)
74{
75	clear_segment_descriptor(desc);
76
77	// In 64-bit mode the CPU ignores the base/limit of code/data segments,
78	// it always treats base as 0 and does no limit checks.
79	desc->base0 = 0;
80	desc->base1 = 0;
81	desc->limit0 = 0xffff;
82	desc->limit1 = 0xf;
83	desc->granularity = 1;
84
85	desc->type = type;
86	desc->desc_type = DT_CODE_DATA_SEGMENT;
87	desc->dpl = dpl;
88	desc->present = 1;
89
90	desc->long_mode = (type & DT_CODE_EXECUTE_ONLY) ? 1 : 0;
91		// Must be set to 1 for code segments only.
92}
93
94
95unsigned x86_64_set_user_tls_segment_base(int cpu, addr_t base);
96
97
98#endif	/* _ASSEMBLER */
99
100#endif	/* _KERNEL_ARCH_X86_64_DESCRIPTORS_H */
101