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 isr start, n
109int_\n\()_for_\start:
110    mov $\n, %rax
111    movq $0, (EXIT_TEST_ADDR)
112.endm
113
114.macro idt start, n
115    .2byte ABSOLUTE_ADDR(\start, \
116                         int_\n\()_for_\start)      // Offset 15:00
117    .2byte CODE_64_SELECTOR                         // Segment selector
118    .byte  0                                        // IST(000)
119    .byte  0b10001110                               // P(1) DPL(00) 0 Type(1110)
120    .2byte 0                                        // Offset 31:16
121    .4byte 0                                        // Offset 63:32
122    .4byte 0                                        // Reserved
123.endm
124
125.macro init_interrupt_handling start
126    init_gdt \start
127    lidt ABSOLUTE_ADDR(\start, idtr_for_\start)
128    mov $GUEST_ENTRY + 0x1000, %rsp
129    jmp end_of_\start
130
131.irp n, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, \
132       16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
133    isr \start \n
134.endr
135
136.align 8
137idt_for_\start:
138.irp n, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, \
139       16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
140    idt \start \n
141.endr
142
143idtr_for_\start:
144    .2byte idtr_for_\start - idt_for_\start - 1     // Limit
145    .8byte ABSOLUTE_ADDR(\start, idt_for_\start)    // Address
146end_of_\start:
147.endm
148
149// Test vcpu_resume.
150FUNCTION vcpu_resume_start
151    // Test that we do not exit on load/store of CR3.
152    mov %cr3, %rax
153    mov %rax, %cr3
154
155    // Test that we do not exit on store of GS_BASE.
156    xor %eax, %eax
157    xor %edx, %edx
158    mov $IA32_GS_BASE, %ecx
159    wrmsr
160
161    // Test that we handle CPUID instruction correctly.
162    xor %eax, %eax
163    cpuid
164
165    movq $0, (EXIT_TEST_ADDR)
166FUNCTION vcpu_resume_end
167
168// Test vcpu_interrupt.
169FUNCTION vcpu_interrupt_start
170    init_interrupt_handling vcpu_interrupt_start
171    sti
172    movq $0, (EXIT_TEST_ADDR)
173    jmp .
174FUNCTION vcpu_interrupt_end
175
176// Test guest HLT instruction handling.
177FUNCTION vcpu_hlt_start
178    init_interrupt_handling vcpu_hlt_start
179    sti
180    hlt
181FUNCTION vcpu_hlt_end
182
183// Test that pause exiting works correctly.
184FUNCTION vcpu_pause_start
185    pause
186    movq $0, (EXIT_TEST_ADDR)
187FUNCTION vcpu_pause_end
188
189// Test that reading and writing cr0 works correctly.
190FUNCTION vcpu_write_cr0_start
191    // Read cr0.
192    mov %cr0, %rax
193
194    // Write cr0 and negate the NE bit.
195    and $~X86_CR0_NE, %rax
196    mov %rax, %cr0
197
198    // Test cr0 masking. NE bit should be set.
199    mov %cr0, %rax
200
201    movq $0, (EXIT_TEST_ADDR)
202FUNCTION vcpu_write_cr0_end
203
204// Test vcpu_read_state and vcpu_write_state.
205FUNCTION vcpu_read_write_state_start
206    add $1, %rax
207    add $2, %rcx
208    add $3, %rdx
209    add $4, %rbx
210    add $5, %rsp
211    add $6, %rbp
212    add $7, %rsi
213    add $8, %rdi
214    add $9, %r8
215    add $10, %r9
216    add $11, %r10
217    add $12, %r11
218    add $13, %r12
219    add $14, %r13
220    add $15, %r14
221    add $16, %r15
222
223    stc  // Set carry flag (bit 0)
224    stac // Set AC flag (bit 18)
225
226    movq $0, (EXIT_TEST_ADDR)
227FUNCTION vcpu_read_write_state_end
228
229// Test 32 bit compatibility mode (long mode disabled).
230FUNCTION vcpu_compat_mode_start
231    init_gdt vcpu_compat_mode_start
232    movq $0, %rbx
233    movq $0, %rcx
234
235    // Drop into compatibility mode
236    pushq $CODE_32_SELECTOR
237    lea vcpu_compat_mode_code(%rip),%rax
238    pushq %rax
239    lretq
240
241.code32
242vcpu_compat_mode_code:
243    // Hack to check if we're x86 or x64. In x86, 0x41 is `inc %ecx` and loop
244    // falls through. In x64, 0x41 is the REX.B prefix and %ecx is not
245    // incremented so loop jmps to vcpu_compat_mode_exit.
246    xor %ecx,%ecx
247    .byte 0x41 // x86: inc %ecx; x64: rex.B prefix
248    loop vcpu_compat_mode_exit
249
250    // Write a value to ebx to check in guest.cpp
251    mov $1,%ebx
252
253    // Go back to long mode
254    pushl $CODE_64_SELECTOR
255    pushl $ABSOLUTE_ADDR(vcpu_compat_mode_start, vcpu_compat_mode_test16)
256    lret
257.code64
258
259vcpu_compat_mode_test16:
260    // Drop into compatibility mode with 16 bit default operands.
261    pushq $CODE_16_SELECTOR
262    lea vcpu_compat_mode_code16(%rip),%rax
263    pushq %rax
264    lretq
265
266.code32
267vcpu_compat_mode_code16:
268    // The default operand size should be 16 bits and push should subtract 2
269    // from the stack pointer.
270    mov %esp,%eax
271    sub $2,%eax
272    push $0
273    cmp %esp,%eax
274    pop %eax
275    jne vcpu_compat_mode_code16_done
276
277    // Write a value to ebx to check in guest.cpp
278    mov $2,%ecx
279
280    // Go back to long mode
281vcpu_compat_mode_code16_done:
282    pushl $CODE_64_SELECTOR
283    pushl $ABSOLUTE_ADDR(vcpu_compat_mode_start, vcpu_compat_mode_done)
284    lret
285.code64
286
287vcpu_compat_mode_done:
288    // Fix the data segment selectors
289    mov $DATA_SELECTOR,%rax
290    mov %rax,%ds
291    mov %rax,%es
292    mov %rax,%fs
293    mov %rax,%gs
294    mov %rax,%ss
295
296vcpu_compat_mode_exit:
297    movq $0, (EXIT_TEST_ADDR)
298FUNCTION vcpu_compat_mode_end
299
300FUNCTION vcpu_syscall_start
301    init_interrupt_handling vcpu_syscall_start
302
303    xor %eax, %eax
304    mov $((USER_CODE_32_SELECTOR << 16) | CODE_64_SELECTOR), %edx
305    mov $X86_MSR_IA32_STAR, %ecx
306    wrmsr
307
308    xor %edx, %edx
309    mov $ABSOLUTE_ADDR(vcpu_syscall_start, vcpu_syscall_done), %eax
310    mov $X86_MSR_IA32_LSTAR, %ecx
311    wrmsr
312
313    pushfq
314    pop %r11
315    mov $ABSOLUTE_ADDR(vcpu_syscall_start, vcpu_syscall_ring3), %rcx
316    sysretq
317
318vcpu_syscall_ring3:
319    syscall
320
321vcpu_syscall_done:
322    movq $0, (EXIT_TEST_ADDR)
323FUNCTION vcpu_syscall_end
324
325FUNCTION vcpu_sysenter_start
326    init_interrupt_handling vcpu_sysenter_start
327
328    xor %edx, %edx
329    mov $CODE_64_SELECTOR, %eax
330    mov $X86_MSR_IA32_SYSENTER_CS, %ecx
331    wrmsr
332
333    mov $ABSOLUTE_ADDR(vcpu_sysenter_start, vcpu_sysenter_done), %eax
334    mov $X86_MSR_IA32_SYSENTER_EIP, %ecx
335    wrmsr
336
337    mov %esp, %eax
338    mov $X86_MSR_IA32_SYSENTER_ESP, %ecx
339    wrmsr
340
341    mov %rsp, %rdx
342    mov $ABSOLUTE_ADDR(vcpu_sysenter_start, vcpu_sysenter_ring3), %rdx
343    .byte 0x48 // rex.W
344    sysexit
345
346vcpu_sysenter_ring3:
347    sysenter
348
349vcpu_sysenter_done:
350    movq $0, (EXIT_TEST_ADDR)
351FUNCTION vcpu_sysenter_end
352
353FUNCTION vcpu_sysenter_compat_start
354    init_interrupt_handling vcpu_sysenter_compat_start
355
356    xor %edx, %edx
357    mov $CODE_64_SELECTOR, %eax
358    mov $X86_MSR_IA32_SYSENTER_CS, %ecx
359    wrmsr
360
361    mov $ABSOLUTE_ADDR(vcpu_sysenter_compat_start, vcpu_sysenter_compat_done), %eax
362    mov $X86_MSR_IA32_SYSENTER_EIP, %ecx
363    wrmsr
364
365    mov %esp, %eax
366    mov $X86_MSR_IA32_SYSENTER_ESP, %ecx
367    wrmsr
368
369    mov %rsp, %rdx
370    mov $ABSOLUTE_ADDR(vcpu_sysenter_compat_start, vcpu_sysenter_compat_ring3), %rdx
371    sysexit
372
373.code32
374vcpu_sysenter_compat_ring3:
375    sysenter
376.code64
377
378vcpu_sysenter_compat_done:
379    movq $0, (EXIT_TEST_ADDR)
380FUNCTION vcpu_sysenter_compat_end
381
382// Test guest_set_trap using a memory-based trap.
383FUNCTION guest_set_trap_start
384    movq $0, (TRAP_ADDR)
385    movq $0, (EXIT_TEST_ADDR)
386FUNCTION guest_set_trap_end
387
388// Test guest_set_trap using an IO-based trap.
389FUNCTION guest_set_trap_with_io_start
390    out %al, $TRAP_PORT
391    movq $0, (EXIT_TEST_ADDR)
392FUNCTION guest_set_trap_with_io_end
393
394FUNCTION vcpu_vmcall_start
395    movq $(INVALID_HYPERCALL), %rax
396    vmcall
397    movq $0, (EXIT_TEST_ADDR)
398FUNCTION vcpu_vmcall_end
399