summaryrefslogtreecommitdiffstats
path: root/tboot/include/processor.h
blob: 83b9fe4e33f1ced347010fef68ce313e14244e40 (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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/* Copyright (c) 1991 The Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */
/*
 * Portions copyright (c) 2010, Intel Corporation
 */

#ifndef __PROCESSOR_H__
#define __PROCESSOR_H__

/* from: @(#)specialreg.h  7.1 (Berkeley) 5/9/91
 * $FreeBSD: stable/8/sys/i386/include/specialreg.h 198989 2009-11-06 15:24:48Z attilio $
 */

/*
 * EFLAGS bits
 */
#define X86_EFLAGS_CF	0x00000001 /* Carry Flag */
#define X86_EFLAGS_PF	0x00000004 /* Parity Flag */
#define X86_EFLAGS_AF	0x00000010 /* Auxillary carry Flag */
#define X86_EFLAGS_ZF	0x00000040 /* Zero Flag */
#define X86_EFLAGS_SF	0x00000080 /* Sign Flag */
#define X86_EFLAGS_TF	0x00000100 /* Trap Flag */
#define X86_EFLAGS_IF	0x00000200 /* Interrupt Flag */
#define X86_EFLAGS_DF	0x00000400 /* Direction Flag */
#define X86_EFLAGS_OF	0x00000800 /* Overflow Flag */
#define X86_EFLAGS_IOPL	0x00003000 /* IOPL mask */
#define X86_EFLAGS_NT	0x00004000 /* Nested Task */
#define X86_EFLAGS_RF	0x00010000 /* Resume Flag */
#define X86_EFLAGS_VM	0x00020000 /* Virtual Mode */
#define X86_EFLAGS_AC	0x00040000 /* Alignment Check */
#define X86_EFLAGS_VIF	0x00080000 /* Virtual Interrupt Flag */
#define X86_EFLAGS_VIP	0x00100000 /* Virtual Interrupt Pending */
#define X86_EFLAGS_ID	0x00200000 /* CPUID detection flag */

/*
 * Bits in 386 special registers:
 */
#define CR0_PE  0x00000001 /* Protected mode Enable */
#define CR0_MP  0x00000002 /* "Math" (fpu) Present */
#define CR0_EM  0x00000004 /* EMulate FPU instructions. (trap ESC only) */
#define CR0_TS  0x00000008 /* Task Switched (if MP, trap ESC and WAIT) */
#define CR0_ET  0x00000010 /* Extension type */
#define CR0_PG  0x80000000 /* PaGing enable */

/*
 * Bits in 486 special registers:
 */
#define CR0_NE  0x00000020 /* Numeric Error enable (EX16 vs IRQ13) */
#define CR0_WP  0x00010000 /* Write Protect (honor page protect in all modes) */
#define CR0_AM  0x00040000 /* Alignment Mask (set to enable AC flag) */
#define CR0_NW  0x20000000 /* Not Write-through */
#define CR0_CD  0x40000000 /* Cache Disable */

/*
 * Bits in PPro special registers
 */
#define CR4_VME 0x00000001 /* Virtual 8086 mode extensions */
#define CR4_PVI 0x00000002 /* Protected-mode virtual interrupts */
#define CR4_TSD 0x00000004 /* Time stamp disable */
#define CR4_DE  0x00000008 /* Debugging extensions */
#define CR4_PSE 0x00000010 /* Page size extensions */
#define CR4_PAE 0x00000020 /* Physical address extension */
#define CR4_MCE 0x00000040 /* Machine check enable */
#define CR4_PGE 0x00000080 /* Page global enable */
#define CR4_PCE 0x00000100 /* Performance monitoring counter enable */
#define CR4_FXSR 0x00000200/* Fast FPU save/restore used by OS */
#define CR4_XMM 0x00000400 /* enable SIMD/MMX2 to use except 16 */
#define CR4_VMXE 0x00002000/* enable VMX */
#define CR4_SMXE 0x00004000/* enable SMX */
#define CR4_PCIDE 0x00020000/* enable PCID */

#ifndef __ASSEMBLY__

/* from:
 * $FreeBSD: src/sys/i386/include/cpufunc.h,v 1.158 2010/01/01 20:55:11 obrien Exp $
 */

static inline void do_cpuid(unsigned int ax, uint32_t *p)
{
    __asm__ __volatile__ ("cpuid"
                          : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
                          :  "0" (ax));
}

static inline void do_cpuid1(unsigned int ax, unsigned int cx, uint32_t *p)
{
    __asm__ __volatile__ ("cpuid"
                          : "=a" (p[0]), "=b" (p[1]), "=c" (p[2]), "=d" (p[3])
                          :  "0" (ax), "c" (cx));
}

static always_inline uint32_t cpuid_eax(unsigned int op)
{
     /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */
    uint32_t regs[4];

    do_cpuid(op, regs);

    return regs[0];
}

static always_inline uint32_t cpuid_ebx(unsigned int op)
{
     /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */
    uint32_t regs[4];

    do_cpuid(op, regs);

    return regs[1];
}

static always_inline uint32_t cpuid_ebx1(unsigned int op1, unsigned int op2)
{
     /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */
    uint32_t regs[4];

    do_cpuid1(op1, op2, regs);

    return regs[1];
}
static always_inline uint32_t cpuid_ecx(unsigned int op)
{
     /* eax: regs[0], ebx: regs[1], ecx: regs[2], edx: regs[3] */
    uint32_t regs[4];

    do_cpuid(op, regs);

    return regs[2];
}

#define CPUID_X86_FEATURE_XMM3   (1<<0)
#define CPUID_X86_FEATURE_VMX    (1<<5)
#define CPUID_X86_FEATURE_SMX    (1<<6)

/* Note, removed read/write ecx, not used */

static inline unsigned long long read_cr0(void)
{
    unsigned long long data;
    /* 64: movl -> movq */
    __asm__ __volatile__ ("movq %%cr0,%0" : "=r" (data));
    return (data);
}

static inline void write_cr0(unsigned long long data)
{
    /* 64: movl -> movq */
    __asm__ __volatile__("movq %0,%%cr0" : : "r" (data));
}

static inline unsigned long long read_cr4(void)
{
    unsigned long long data;
    /* 64: movl -> movq */
    __asm__ __volatile__ ("movq %%cr4,%0" : "=r" (data));
    return (data);
}

static inline void write_cr4(unsigned long long data)
{
    /* 64: movl -> movq */
    __asm__ __volatile__ ("movq %0,%%cr4" : : "r" (data));
}

static inline unsigned long long read_cr3(void)
{
    unsigned long long data;
    /* 64: movl -> movq */
    __asm__ __volatile__ ("movq %%cr3,%0" : "=r" (data));
    return (data);
}

static inline void write_cr3(unsigned long long data)
{
    /* 64: movl -> movq */
    __asm__ __volatile__("movq %0,%%cr3" : : "r" (data) : "memory");
}

static inline uint64_t read_rflags(void)
{
    uint64_t rf;
    /* 32: EFLAGS stuff __asm__ __volatile__ ("pushfl; popl %0" : "=r" (ef));*/
    __asm__ __volatile__ ("pushfq; popq %0" : "=r" (rf));
    return (rf);
}

static inline void write_rflags(uint64_t rf)
{
    /* 32: EFLAGS stuff __asm__ __volatile__ ("pushl %0; popfl" : : "r" (ef));*/
    __asm__ __volatile__ ("pushq %0; popfq" : : "r" (rf));
}

static inline void disable_intr(void)
{
    __asm__ __volatile__ ("cli" : : : "memory");
}

static inline void enable_intr(void)
{
    __asm__ __volatile__ ("sti");
}

/* was ia32_pause() */
static inline void cpu_relax(void)
{
    __asm__ __volatile__ ("pause");
}

static inline void halt(void)
{
    __asm__ __volatile__ ("hlt");
}

static inline unsigned int get_apicid(void)
{
    return cpuid_ebx(1) >> 24;
}

static inline void wbinvd(void)
{
    __asm__ __volatile__ ("wbinvd");
}

static inline uint32_t bsrl(uint32_t mask)
{
    uint32_t   result;

    /* 64: Ok to shift 32b mask */
    __asm__ __volatile__ ("bsrl %1,%0" : "=r" (result) : "rm" (mask) : "cc");
    return (result);
}

static inline int fls(int mask)
{
    return (mask == 0 ? mask : (int)bsrl((u_int)mask) + 1);
}

static always_inline void mb(void)
{
    /* 32: __asm__ __volatile__ ("lock;addl $0,0(%%esp)" : : : "memory"); */
    __asm__ __volatile__ ("lock;addq $0,0(%%rsp)" : : : "memory");
}

static inline void cpu_monitor(const void *addr, int extensions, int hints)
{
    /* 64: a=rax, c=rcx, d=rdx  ints are 32b into ecx, edx */
    __asm __volatile__ ("monitor;" : :"a" (addr), "c" (extensions), "d"(hints));
}

static inline void cpu_mwait(int extensions, int hints)
{
    /* 64: a=rax, c=rcx  ints are 32b into eax, ecx */
    __asm __volatile__ ("mwait;" : :"a" (hints), "c" (extensions));
}

static inline void flush_tlb(void)
{
    __asm__ __volatile__ (
                   "movq %%cr3, %%rax\n"
                   "movq %%rax, %%cr3\n"
                   : : : "rax");
}

typedef struct __packed lmode_desc {
    uint16_t limit;
    uint64_t base;
} lmode_desc_t;

static inline void store_gdt(lmode_desc_t *gdt)
{
    __asm__ __volatile__("sgdt %0\n\t"
                         : "=m" (*gdt) : : "memory");
}

static inline void store_idt(lmode_desc_t *idt)
{
    __asm__ __volatile__("sidt %0\n\t"
                         : "=m" (*idt): : "memory");
}

#define lea_reference(i, o) __asm__ __volatile__ \
      ("lea "#i"(%%rip), %%rax\n\t" : "=a" (o))

#define mov_sel(r, o) __asm__ __volatile__ \
    ("movw %%"#r"s, %0\n\t" : "=m" (o) : : "memory");

/* In inline asm, these 3 use the A constraint to specify the EDX:EAX register
 * pair. The inline assembler was getting the code badly wrong so the
 * implementation of these moved to the assembly module (and renamed).
 */
uint64_t read_msr(uint32_t msr);
void write_msr(uint32_t msr, uint64_t newval);
uint64_t read_tsc(void);

uint64_t get_rip(void);
uint64_t bsp_stack_ref(void);

#define rdmsr read_msr
#define wrmsr write_msr
#define rdtsc read_tsc

#endif /* __ASSEMBLY__ */

#endif /* __PROCESSOR_H__ */

/*
 * Local variables:
 * mode: C
 * c-set-style: "BSD"
 * c-basic-offset: 4
 * tab-width: 4
 * indent-tabs-mode: nil
 * End:
 */