summaryrefslogtreecommitdiff
path: root/arch/x86/machine/cpu_i.h
blob: ffea8db8eb22a7a98faca530190241e64acff53f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
/*
 * Copyright (c) 2018 Richard Braun.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef X86_CPU_I_H
#define X86_CPU_I_H

/*
 * Exception frame offets.
 */

#ifdef __LP64__

#define CPU_EXC_FRAME_RAX       0
#define CPU_EXC_FRAME_RBX       1
#define CPU_EXC_FRAME_RCX       2
#define CPU_EXC_FRAME_RDX       3
#define CPU_EXC_FRAME_RBP       4
#define CPU_EXC_FRAME_RSI       5
#define CPU_EXC_FRAME_RDI       6
#define CPU_EXC_FRAME_R8        7
#define CPU_EXC_FRAME_R9        8
#define CPU_EXC_FRAME_R10       9
#define CPU_EXC_FRAME_R11       10
#define CPU_EXC_FRAME_R12       11
#define CPU_EXC_FRAME_R13       12
#define CPU_EXC_FRAME_R14       13
#define CPU_EXC_FRAME_R15       14
#define CPU_EXC_FRAME_VECTOR    15
#define CPU_EXC_FRAME_ERROR     16
#define CPU_EXC_FRAME_RIP       17
#define CPU_EXC_FRAME_CS        18
#define CPU_EXC_FRAME_RFLAGS    19
#define CPU_EXC_FRAME_RSP       20
#define CPU_EXC_FRAME_SS        21
#define CPU_EXC_FRAME_SIZE      22

#define CPU_EXC_FRAME_FP        CPU_EXC_FRAME_RBP
#define CPU_EXC_FRAME_SP        CPU_EXC_FRAME_RSP
#define CPU_EXC_FRAME_PC        CPU_EXC_FRAME_RIP

#else /* __LP64__ */

#define CPU_EXC_FRAME_EAX       0
#define CPU_EXC_FRAME_EBX       1
#define CPU_EXC_FRAME_ECX       2
#define CPU_EXC_FRAME_EDX       3
#define CPU_EXC_FRAME_EBP       4
#define CPU_EXC_FRAME_ESI       5
#define CPU_EXC_FRAME_EDI       6
#define CPU_EXC_FRAME_DS        7
#define CPU_EXC_FRAME_ES        8
#define CPU_EXC_FRAME_FS        9
#define CPU_EXC_FRAME_GS        10
#define CPU_EXC_FRAME_VECTOR    11
#define CPU_EXC_FRAME_ERROR     12
#define CPU_EXC_FRAME_EIP       13
#define CPU_EXC_FRAME_CS        14
#define CPU_EXC_FRAME_EFLAGS    15
#define CPU_EXC_FRAME_ESP       16
#define CPU_EXC_FRAME_SS        17 /* esp and ss are undefined if trapped in kernel */
#define CPU_EXC_FRAME_SIZE      18

#define CPU_EXC_FRAME_FP        CPU_EXC_FRAME_EBP
#define CPU_EXC_FRAME_SP        CPU_EXC_FRAME_ESP
#define CPU_EXC_FRAME_PC        CPU_EXC_FRAME_EIP

#endif /* __LP64__ */

/*
 * EFLAGS register flags.
 */
#define CPU_EFL_ONE 0x00000002  /* Reserved, must be set */
#define CPU_EFL_IF  0x00000200

/*
 * GDT segment selectors.
 *
 * Keep in mind that, on amd64, the size of a GDT entry referred to
 * by a selector depends on the descriptor type.
 */
#define CPU_GDT_SEL_NULL        0
#define CPU_GDT_SEL_CODE        8
#define CPU_GDT_SEL_DATA        16
#define CPU_GDT_SEL_TSS         24

#ifdef __LP64__
#define CPU_GDT_SIZE            40
#else /* __LP64__ */
#define CPU_GDT_SEL_DF_TSS      32
#define CPU_GDT_SEL_PERCPU      40
#define CPU_GDT_SEL_TLS         48
#define CPU_GDT_SIZE            56
#endif /* __LP64__ */

#ifndef __ASSEMBLER__

#include <stdalign.h>
#include <stdbool.h>
#include <stdint.h>

#include <kern/bitmap.h>

struct cpu_tss {
#ifdef __LP64__
    uint32_t reserved0;
    uint64_t rsp0;
    uint64_t rsp1;
    uint64_t rsp2;
    uint64_t ist[8];
    uint64_t reserved1;
    uint16_t reserved2;
#else /* __LP64__ */
    uint32_t link;
    uint32_t esp0;
    uint32_t ss0;
    uint32_t esp1;
    uint32_t ss1;
    uint32_t esp2;
    uint32_t ss2;
    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;
    uint32_t es;
    uint32_t cs;
    uint32_t ss;
    uint32_t ds;
    uint32_t fs;
    uint32_t gs;
    uint32_t ldt;
    uint16_t trap_bit;
#endif /* __LP64__ */
    uint16_t iobp_base;
} __packed;

/*
 * LDT or TSS system segment descriptor.
 */
struct cpu_sysseg_desc {
    uint32_t word1;
    uint32_t word2;
#ifdef __LP64__
    uint32_t word3;
    uint32_t word4;
#endif /* __LP64__ */
};

struct cpu_gdt {
    alignas(CPU_L1_SIZE) char descs[CPU_GDT_SIZE];
};

#define CPU_VENDOR_ID_SIZE  13
#define CPU_MODEL_NAME_SIZE 49

struct cpu_feature_map {
    BITMAP_DECLARE(flags, CPU_NR_FEATURES);
};

struct cpu {
    unsigned int id;
    unsigned int apic_id;
    char vendor_str[CPU_VENDOR_STR_SIZE];
    char model_name[CPU_MODEL_NAME_SIZE];
    unsigned int cpuid_max_basic;
    unsigned int cpuid_max_extended;
    unsigned int vendor_id;
    unsigned int type;
    unsigned int family;
    unsigned int model;
    unsigned int stepping;
    unsigned int clflush_size;
    unsigned int initial_apic_id;
    struct cpu_feature_map feature_map;
    unsigned short phys_addr_width;
    unsigned short virt_addr_width;

    struct cpu_gdt gdt;

    /*
     * TSS segments, one set per CPU.
     *
     * One TSS at least is required per processor to provide the following :
     *  - stacks for double fault handlers, implemented with task switching
     *    on i386, interrupt stack tables on amd64
     *  - stacks for each privilege level
     *  - I/O permission bitmaps
     *
     * See Intel 64 and IA-32 Architecture Software Developer's Manual,
     * Volume 3 System Programming Guide :
     *  - 6.12.2 Interrupt tasks
     *  - 7.3 Task switching
     */
    struct cpu_tss tss;
#ifndef __LP64__
    struct cpu_tss df_tss;
#endif /* __LP64__ */

    unsigned int started;

    alignas(CPU_DATA_ALIGN) char intr_stack[CPU_INTR_STACK_SIZE];
    alignas(CPU_DATA_ALIGN) char df_stack[CPU_INTR_STACK_SIZE];
};

/*
 * This percpu variable contains the address of the percpu area for the local
 * processor. This is normally the same value stored in the percpu module, but
 * it can be directly accessed through a segment register.
 */
extern void *cpu_local_area;

static inline bool
cpu_feature_map_test(const struct cpu_feature_map *map,
                     enum cpu_feature feature)
{
    return bitmap_test(map->flags, feature);
}

/*
 * Return the content of the EFLAGS register.
 *
 * Implies a compiler barrier.
 *
 * TODO Add cpu_flags_t type.
 */
static __always_inline unsigned long
cpu_get_eflags(void)
{
    unsigned long eflags;

    asm volatile("pushf\n"
                 "pop %0\n"
                 : "=r" (eflags)
                 : : "memory");

    return eflags;
}

#endif /* __ASSEMBLER__ */

#endif /* X86_CPU_I_H */