1// Copyright 2017 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#include "constants_priv.h"
8
9#define IA32_GS_BASE              0xc0000101
10#define X86_MSR_IA32_STAR         0xc0000081
11#define X86_MSR_IA32_LSTAR        0xc0000082
12#define X86_MSR_IA32_SYSENTER_CS  0x00000174
13#define X86_MSR_IA32_SYSENTER_ESP 0x00000175
14#define X86_MSR_IA32_SYSENTER_EIP 0x00000176
15#define X86_MSR_IA32_EFER         0xc0000080
16#define ABSOLUTE_ADDR(base, x)    (x - base + GUEST_ENTRY)
17#define CODE_32_SELECTOR          (1<<3)
18#define CODE_64_SELECTOR          (2<<3)
19#define DATA_SELECTOR             (3<<3)
20#define USER_CODE_32_SELECTOR     (4<<3)
21#define USER_DATA_SELECTOR        (5<<3)
22#define USER_CODE_64_SELECTOR     (6<<3)
23#define CODE_16_SELECTOR          (8<<3)
24#define INVALID_HYPERCALL         0xffffffff
25
26.text
27
28// Define new function 'name'.
29// Local label '1:' used by other macros to compute offsets.
30.macro FUNCTION name
31    .global \name
32    .type \name, STT_FUNC
33    \name:
34    1:
35.endm
36
37.macro init_gdt start
38    lgdt ABSOLUTE_ADDR(\start, gdtr_for_\start)
39    mov $GUEST_ENTRY + 0x1000, %rsp
40    jmp end_of_init_gdt_for_\start
41
42.align 8
43gdt_for_\start:
44    // Null entry.
45    .8byte 0
46    // CODE_32_SELECTOR
47    .2byte 0xffff                                   // Limit 15:00
48    .2byte 0x0000                                   // Base 15:00
49    .byte  0x00                                     // Base 23:16
50    .byte  0b10011010                               // P(1) DPL(00) S(1) 1 C(0) R(1) A(0)
51    .byte  0b11001111                               // G(1) D(1) L(0) AVL(0) Limit 19:16
52    .byte  0x0                                      // Base 31:24
53    // CODE_64_SELECTOR
54    .2byte 0xffff                                   // Limit 15:00
55    .2byte 0x0000                                   // Base 15:00
56    .byte  0x00                                     // Base 23:16
57    .byte  0b10011010                               // P(1) DPL(00) S(1) 1 C(0) R(1) A(0)
58    .byte  0b10101111                               // G(1) D(0) L(1) AVL(0) Limit 19:16
59    .byte  0x0                                      // Base 31:24
60    // DATA_SELECTOR
61    .2byte 0xffff                                   // Limit 15:00
62    .2byte 0x0000                                   // Base 15:00
63    .byte  0x00                                     // Base 23:16
64    .byte  0b10010010                               // P(1) DPL(00) S(1) 0 E(0) W(1) A(0)
65    .byte  0b11001111                               // G(1) B(1) L(0) AVL(0) Limit 19:16
66    .byte  0x0                                      // Base 31:24
67    // USER_CODE_32_SELECTOR
68    .2byte 0xffff                                   // Limit 15:00
69    .2byte 0x0000                                   // Base 15:00
70    .byte  0x00                                     // Base 23:16
71    .byte  0b11111010                               // P(1) DPL(11) S(1) 1 C(0) R(1) A(0)
72    .byte  0b11001111                               // G(1) D(1) L(0) AVL(0) Limit 19:16
73    .byte  0x0                                      // Base 31:24
74    // USER_DATA_SELECTOR
75    .2byte 0xffff                                   // Limit 15:00
76    .2byte 0x0000                                   // Base 15:00
77    .byte  0x00                                     // Base 23:16
78    .byte  0b11110010                               // P(1) DPL(11) S(1) 0 E(0) W(1) A(0)
79    .byte  0b11001111                               // G(1) B(1) 0 0 limit 19:16
80    .byte  0x0                                      // Base 31:24
81    // USER_CODE_64_SELECTOR
82    .2byte 0xffff                                   // Limit 15:00
83    .2byte 0x0000                                   // Base 15:00
84    .byte  0x00                                     // Base 23:16
85    .byte  0b11111010                               // P(1) DPL(11) S(1) 1 C(0) R(1) A(0)
86    .byte  0b10101111                               // G(1) D(0) L(1) AVL(0) Limit 19:16
87    .byte  0x0                                      // Base 31:24
88    // USER_DATA_SELECTOR duplicate for sysexit
89    .2byte 0xffff                                   // Limit 15:00
90    .2byte 0x0000                                   // Base 15:00
91    .byte  0x00                                     // Base 23:16
92    .byte  0b11110010                               // P(1) DPL(11) S(1) 0 E(0) W(1) A(0)
93    .byte  0b11001111                               // G(1) B(1) 0 0 limit 19:16
94    .byte  0x0                                      // Base 31:24
95    // CODE_16_SELECTOR
96    .2byte 0xffff                                   // Limit 15:00
97    .2byte 0x0000                                   // Base 15:00
98    .byte  0x00                                     // Base 23:16
99    .byte  0b10011010                               // P(1) DPL(00) S(1) 1 C(0) R(1) A(0)
100    .byte  0b10001111                               // G(1) D(0) L(0) AVL(0) Limit 19:16
101    .byte  0x0                                      // Base 31:24
102gdtr_for_\start:
103    .2byte gdtr_for_\start - gdt_for_\start - 1
104    .8byte ABSOLUTE_ADDR(\start, gdt_for_\start)
105end_of_init_gdt_for_\start:
106.endm
107
108.macro debug_isr start, n
109int_\n\()_for_\start:
110    mov $\n, %rax
111    popq %rbx // Error code
112    popq %rcx // RIP
113    movq $-1, (EXIT_TEST_ADDR)
114.endm
115
116.macro debug_idt start, n
117    .2byte ABSOLUTE_ADDR(\start, \
118                         int_\n\()_for_\start)      // Offset 15:00
119    .2byte CODE_64_SELECTOR                         // Segment selector
120    .byte  0                                        // IST(000)
121    .byte  0b10001110                               // P(1) DPL(00) 0 Type(1110)
122    .2byte 0                                        // Offset 31:16
123    .4byte 0                                        // Offset 63:32
124    .4byte 0                                        // Reserved
125.endm
126
127.macro init_interrupt_handling start
128    init_gdt \start
129    lidt ABSOLUTE_ADDR(\start, idtr_for_\start)
130    mov $GUEST_ENTRY + 0x1000, %rsp
131    jmp end_of_\start
132
133.irp n, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, \
134       16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
135    debug_isr \start \n
136.endr
137
138int32_for_\start:
139    movq $0, (EXIT_TEST_ADDR)
140
141.align 8
142idt_for_\start:
143.irp n, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, \
144       16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
145    debug_idt \start \n
146.endr
147
148    .2byte ABSOLUTE_ADDR(\start, int32_for_\start)  // Offset 15:00
149    .2byte CODE_64_SELECTOR                         // Segment selector
150    .byte  0                                        // IST(000)
151    .byte  0b10001110                               // P(1) DPL(00) 0 Type(1110)
152    .2byte 0                                        // Offset 31:16
153    .4byte 0                                        // Offset 63:32
154    .4byte 0                                        // Reserved
155idtr_for_\start:
156    .2byte idtr_for_\start - idt_for_\start - 1     // Limit
157    .8byte ABSOLUTE_ADDR(\start, idt_for_\start)    // Address
158end_of_\start:
159.endm
160
161// Test vcpu_resume.
162FUNCTION vcpu_resume_start
163    // Test that we do not exit on load/store of CR3.
164    mov %cr3, %rax
165    mov %rax, %cr3
166
167    // Test that we do not exit on store of GS_BASE.
168    xor %eax, %eax
169    xor %edx, %edx
170    mov $IA32_GS_BASE, %ecx
171    wrmsr
172
173    // Test that we handle CPUID instruction correctly.
174    xor %eax, %eax
175    cpuid
176
177    movq $0, (EXIT_TEST_ADDR)
178FUNCTION vcpu_resume_end
179
180// Test vcpu_interrupt.
181FUNCTION vcpu_interrupt_start
182    init_interrupt_handling vcpu_interrupt_start
183    sti
184    jmp .
185FUNCTION vcpu_interrupt_end
186
187// Test guest HLT instruction handling.
188FUNCTION vcpu_hlt_start
189    init_interrupt_handling vcpu_hlt_start
190    sti
191    hlt
192FUNCTION vcpu_hlt_end
193
194// Test that pause exiting works correctly.
195FUNCTION vcpu_pause_start
196    pause
197    movq $0, (EXIT_TEST_ADDR)
198FUNCTION vcpu_pause_end
199
200// Test that reading and writing cr0 works correctly.
201FUNCTION vcpu_write_cr0_start
202    // Read cr0.
203    mov %cr0, %rax
204
205    // Write cr0 and negate the NE bit.
206    and $~X86_CR0_NE, %rax
207    mov %rax, %cr0
208
209    // Test cr0 masking. NE bit should be set.
210    mov %cr0, %rax
211
212    movq $0, (EXIT_TEST_ADDR)
213FUNCTION vcpu_write_cr0_end
214
215// Test vcpu_read_state and vcpu_write_state.
216FUNCTION vcpu_read_write_state_start
217    add $1, %rax
218    add $2, %rcx
219    add $3, %rdx
220    add $4, %rbx
221    add $5, %rsp
222    add $6, %rbp
223    add $7, %rsi
224    add $8, %rdi
225    add $9, %r8
226    add $10, %r9
227    add $11, %r10
228    add $12, %r11
229    add $13, %r12
230    add $14, %r13
231    add $15, %r14
232    add $16, %r15
233
234    stc  // Set carry flag (bit 0)
235    stac // Set AC flag (bit 18)
236
237    movq $0, (EXIT_TEST_ADDR)
238FUNCTION vcpu_read_write_state_end
239
240// Test 32 bit compatibility mode (long mode disabled).
241FUNCTION vcpu_compat_mode_start
242    init_gdt vcpu_compat_mode_start
243    movq $0, %rbx
244    movq $0, %rcx
245
246    // Drop into compatibility mode
247    pushq $CODE_32_SELECTOR
248    lea vcpu_compat_mode_code(%rip),%rax
249    pushq %rax
250    lretq
251
252.code32
253vcpu_compat_mode_code:
254    // Hack to check if we're x86 or x64. In x86, 0x41 is `inc %ecx` and loop
255    // falls through. In x64, 0x41 is the REX.B prefix and %ecx is not
256    // incremented so loop jmps to vcpu_compat_mode_exit.
257    xor %ecx,%ecx
258    .byte 0x41 // x86: inc %ecx; x64: rex.B prefix
259    loop vcpu_compat_mode_exit
260
261    // Write a value to ebx to check in guest.cpp
262    mov $1,%ebx
263
264    // Go back to long mode
265    pushl $CODE_64_SELECTOR
266    pushl $ABSOLUTE_ADDR(vcpu_compat_mode_start, vcpu_compat_mode_test16)
267    lret
268.code64
269
270vcpu_compat_mode_test16:
271    // Drop into compatibility mode with 16 bit default operands.
272    pushq $CODE_16_SELECTOR
273    lea vcpu_compat_mode_code16(%rip),%rax
274    pushq %rax
275    lretq
276
277.code32
278vcpu_compat_mode_code16:
279    // The default operand size should be 16 bits and push should subtract 2
280    // from the stack pointer.
281    mov %esp,%eax
282    sub $2,%eax
283    push $0
284    cmp %esp,%eax
285    pop %eax
286    jne vcpu_compat_mode_code16_done
287
288    // Write a value to ebx to check in guest.cpp
289    mov $2,%ecx
290
291    // Go back to long mode
292vcpu_compat_mode_code16_done:
293    pushl $CODE_64_SELECTOR
294    pushl $ABSOLUTE_ADDR(vcpu_compat_mode_start, vcpu_compat_mode_done)
295    lret
296.code64
297
298vcpu_compat_mode_done:
299    // Fix the data segment selectors
300    mov $DATA_SELECTOR,%rax
301    mov %rax,%ds
302    mov %rax,%es
303    mov %rax,%fs
304    mov %rax,%gs
305    mov %rax,%ss
306
307vcpu_compat_mode_exit:
308    movq $0, (EXIT_TEST_ADDR)
309FUNCTION vcpu_compat_mode_end
310
311FUNCTION vcpu_syscall_start
312    init_interrupt_handling vcpu_syscall_start
313
314    xor %eax, %eax
315    mov $((USER_CODE_32_SELECTOR << 16) | CODE_64_SELECTOR), %edx
316    mov $X86_MSR_IA32_STAR, %ecx
317    wrmsr
318
319    xor %edx, %edx
320    mov $ABSOLUTE_ADDR(vcpu_syscall_start, vcpu_syscall_done), %eax
321    mov $X86_MSR_IA32_LSTAR, %ecx
322    wrmsr
323
324    pushfq
325    pop %r11
326    mov $ABSOLUTE_ADDR(vcpu_syscall_start, vcpu_syscall_ring3), %rcx
327    sysretq
328
329vcpu_syscall_ring3:
330    syscall
331
332vcpu_syscall_done:
333    movq $0, (EXIT_TEST_ADDR)
334FUNCTION vcpu_syscall_end
335
336FUNCTION vcpu_sysenter_start
337    init_interrupt_handling vcpu_sysenter_start
338
339    xor %edx, %edx
340    mov $CODE_64_SELECTOR, %eax
341    mov $X86_MSR_IA32_SYSENTER_CS, %ecx
342    wrmsr
343
344    mov $ABSOLUTE_ADDR(vcpu_sysenter_start, vcpu_sysenter_done), %eax
345    mov $X86_MSR_IA32_SYSENTER_EIP, %ecx
346    wrmsr
347
348    mov %esp, %eax
349    mov $X86_MSR_IA32_SYSENTER_ESP, %ecx
350    wrmsr
351
352    mov %rsp, %rdx
353    mov $ABSOLUTE_ADDR(vcpu_sysenter_start, vcpu_sysenter_ring3), %rdx
354    .byte 0x48 // rex.W
355    sysexit
356
357vcpu_sysenter_ring3:
358    sysenter
359
360vcpu_sysenter_done:
361    movq $0, (EXIT_TEST_ADDR)
362FUNCTION vcpu_sysenter_end
363
364FUNCTION vcpu_sysenter_compat_start
365    init_interrupt_handling vcpu_sysenter_compat_start
366
367    xor %edx, %edx
368    mov $CODE_64_SELECTOR, %eax
369    mov $X86_MSR_IA32_SYSENTER_CS, %ecx
370    wrmsr
371
372    mov $ABSOLUTE_ADDR(vcpu_sysenter_compat_start, vcpu_sysenter_compat_done), %eax
373    mov $X86_MSR_IA32_SYSENTER_EIP, %ecx
374    wrmsr
375
376    mov %esp, %eax
377    mov $X86_MSR_IA32_SYSENTER_ESP, %ecx
378    wrmsr
379
380    mov %rsp, %rdx
381    mov $ABSOLUTE_ADDR(vcpu_sysenter_compat_start, vcpu_sysenter_compat_ring3), %rdx
382    sysexit
383
384.code32
385vcpu_sysenter_compat_ring3:
386    sysenter
387.code64
388
389vcpu_sysenter_compat_done:
390    movq $0, (EXIT_TEST_ADDR)
391FUNCTION vcpu_sysenter_compat_end
392
393// Test guest_set_trap using a memory-based trap.
394FUNCTION guest_set_trap_start
395    movq $0, (TRAP_ADDR)
396    movq $0, (EXIT_TEST_ADDR)
397FUNCTION guest_set_trap_end
398
399// Test guest_set_trap using an IO-based trap.
400FUNCTION guest_set_trap_with_io_start
401    out %al, $TRAP_PORT
402    movq $0, (EXIT_TEST_ADDR)
403FUNCTION guest_set_trap_with_io_end
404
405FUNCTION vcpu_vmcall_start
406    movq $(INVALID_HYPERCALL), %rax
407    vmcall
408    movq $0, (EXIT_TEST_ADDR)
409FUNCTION vcpu_vmcall_end
410