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