descriptors.h revision cd59bf43
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 USER_DATA_SEGMENT		3
14#define USER_CODE_SEGMENT		4
15
16#define KERNEL_CODE_SELECTOR	((KERNEL_CODE_SEGMENT << 3) | DPL_KERNEL)
17#define KERNEL_DATA_SELECTOR	((KERNEL_DATA_SEGMENT << 3) | DPL_KERNEL)
18
19#define USER_CODE_SELECTOR	((USER_CODE_SEGMENT << 3) | DPL_USER)
20#define USER_DATA_SELECTOR	((USER_DATA_SEGMENT << 3) | DPL_USER)
21
22
23#ifndef _ASSEMBLER
24
25
26// Structure of a segment descriptor.
27struct segment_descriptor {
28	uint32 limit0 : 16;
29	uint32 base0 : 24;
30	uint32 type : 4;
31	uint32 desc_type : 1;
32	uint32 dpl : 2;
33	uint32 present : 1;
34	uint32 limit1 : 4;
35	uint32 available : 1;
36	uint32 long_mode : 1;
37	uint32 d_b : 1;
38	uint32 granularity : 1;
39	uint32 base1 : 8;
40} _PACKED;
41
42// Structure of an interrupt descriptor.
43struct interrupt_descriptor {
44	uint32 base0 : 16;
45	uint32 sel : 16;
46	uint32 ist : 3;
47	uint32 unused1 : 5;
48	uint32 type : 4;
49	uint32 unused2 : 1;
50	uint32 dpl : 2;
51	uint32 present : 1;
52	uint32 base1 : 16;
53	uint32 base2 : 32;
54	uint32 reserved : 32;
55} _PACKED;
56
57struct tss {
58	uint32 _reserved1;
59	uint64 sp0;
60	uint64 sp1;
61	uint64 sp2;
62	uint64 _reserved2;
63	uint64 ist1;
64	uint64 ist2;
65	uint64 ist3;
66	uint64 ist4;
67	uint64 ist5;
68	uint64 ist6;
69	uint64 ist7;
70	uint64 _reserved3;
71	uint16 _reserved4;
72	uint16 io_map_base;
73} _PACKED;
74
75
76static inline void
77clear_segment_descriptor(segment_descriptor* desc)
78{
79	*(uint64*)desc = 0;
80}
81
82
83static inline void
84set_segment_descriptor(segment_descriptor* desc, uint8 type, uint8 dpl)
85{
86	clear_segment_descriptor(desc);
87
88	// In 64-bit mode the CPU ignores the base/limit of code/data segments,
89	// it always treats base as 0 and does no limit checks.
90	desc->base0 = 0;
91	desc->base1 = 0;
92	desc->limit0 = 0xffff;
93	desc->limit1 = 0xf;
94	desc->granularity = 1;
95
96	desc->type = type;
97	desc->desc_type = DT_CODE_DATA_SEGMENT;
98	desc->dpl = dpl;
99	desc->present = 1;
100
101	desc->long_mode = (type & DT_CODE_EXECUTE_ONLY) ? 1 : 0;
102		// Must be set to 1 for code segments only.
103}
104
105
106static inline void
107set_interrupt_descriptor(interrupt_descriptor* desc, uint64 addr, uint32 type,
108	uint16 seg, uint32 dpl, uint32 ist)
109{
110	desc->base0 = addr & 0xffff;
111	desc->base1 = (addr >> 16) & 0xffff;
112	desc->base2 = (addr >> 32) & 0xffffffff;
113	desc->sel = seg;
114	desc->ist = ist;
115	desc->type = type;
116	desc->dpl = dpl;
117	desc->present = 1;
118	desc->unused1 = 0;
119	desc->unused2 = 0;
120	desc->reserved = 0;
121}
122
123
124#endif	/* _ASSEMBLER */
125
126#endif	/* _KERNEL_ARCH_X86_64_DESCRIPTORS_H */
127