369 lines
6.7 KiB
ArmAsm
369 lines
6.7 KiB
ArmAsm
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (C) 2020 SUSE LLC
|
|
* Author: Nicolai Stange <nstange@suse.de>
|
|
* LTP port: Martin Doucha <mdoucha@suse.cz>
|
|
*/
|
|
|
|
.set KVM_TEXIT, 0xff
|
|
.set RESULT_ADDRESS, 0xfffff000
|
|
|
|
/*
|
|
* This section will be allocated at address 0x1000 and
|
|
* jumped to from the reset stub provided by kvm_run.
|
|
*/
|
|
.code16
|
|
.section .init.protected_mode, "ax"
|
|
real_mode_entry:
|
|
cli
|
|
|
|
lgdt kvm_gdt_desc
|
|
|
|
mov $0x11, %eax
|
|
mov %eax, %cr0
|
|
|
|
jmp $1 * 8, $protected_mode_entry
|
|
|
|
.code32
|
|
protected_mode_entry:
|
|
mov $2 * 8, %eax
|
|
mov %eax, %ds
|
|
mov %eax, %es
|
|
jmp init_memlayout
|
|
|
|
.section .data.gdt32, "a", @progbits
|
|
|
|
.macro gdt32_entry type:req l=0 d=0 dpl=0 limit=0xfffff g=1 p=1
|
|
.4byte \limit & 0xffff
|
|
.2byte (\type << 8) | (\dpl << 13) | (\p << 15)
|
|
.2byte (\limit >> 16) | (\l << 5) | (\d << 6) | (\g << 7)
|
|
.endm
|
|
.align 8
|
|
.global kvm_gdt
|
|
kvm_gdt:
|
|
.8byte 0
|
|
gdt32_entry type=0x1a l=0 d=1 /* Code segment protected_mode, 32bits */
|
|
gdt32_entry type=0x12 /* Data segment, writable */
|
|
.skip 16 /* Stack and TSS segment descriptors */
|
|
|
|
.Lgdt_end:
|
|
.global kvm_gdt_desc
|
|
kvm_gdt_desc:
|
|
.2byte .Lgdt_end - kvm_gdt - 1
|
|
.4byte kvm_gdt
|
|
|
|
.code32
|
|
.section .init.memlayout, "ax"
|
|
init_memlayout:
|
|
/*
|
|
* Identity-map the first 2GB of virtual address space.
|
|
*/
|
|
lea kvm_pagetable, %edi
|
|
lea kvm_pgtable_l2, %esi
|
|
movl %esi, %eax
|
|
mov $1024, %ecx
|
|
|
|
1: movl %eax, %ebx
|
|
orl $0x3, %ebx /* Flags: present, writable */
|
|
movl %ebx, (%edi)
|
|
addl $4, %edi
|
|
addl $4096, %eax
|
|
dec %ecx
|
|
jnz 1b
|
|
|
|
/* Fill kvm_pgtable_l2 with identity map of the first 2GB. */
|
|
movl %esi, %edi
|
|
movl $512 * 1024, %ecx
|
|
xor %eax, %eax
|
|
|
|
1: movl %eax, %ebx
|
|
orl $0x3, %ebx /* Flags: present, writable */
|
|
movl %ebx, (%edi)
|
|
addl $4, %edi
|
|
addl $4096, %eax
|
|
dec %ecx
|
|
jnz 1b
|
|
|
|
/* Mark the upper 2GB as unmapped except for the last page. */
|
|
movl $512 * 1024 - 1, %ecx
|
|
xor %eax, %eax
|
|
rep stosl
|
|
movl $0xfffff003, (%edi)
|
|
|
|
/*
|
|
* Install new pagetable to CR3 and enable memory paging by setting
|
|
* CR0.WP and CR0.PG
|
|
*/
|
|
lea kvm_pagetable, %eax
|
|
movl %eax, %cr3
|
|
movl %cr0, %eax
|
|
btsl $31, %eax
|
|
btsl $16, %eax
|
|
movl %eax, %cr0
|
|
|
|
/* Init TSS */
|
|
lea kvm_tss, %edx
|
|
movl %edx, %edi
|
|
movl $.Ltss_end - kvm_tss, %ecx
|
|
xor %eax, %eax
|
|
rep stosb
|
|
movl %edx, %edi
|
|
lea kvm_stack_top, %edx
|
|
movl %edx, 4(%edi)
|
|
|
|
/* Create a stack descriptor in the 4th GDT slot */
|
|
/* Base address: 0x0, Limit: kvm_stack_bottom */
|
|
xor %eax, %eax
|
|
movl $0xc09600, %ebx /* flags + access bits */
|
|
movl $kvm_stack_bottom - 1, %edx
|
|
shr $12, %edx
|
|
movw %dx, %ax
|
|
andl $0xf0000, %edx
|
|
orl %edx, %ebx
|
|
|
|
lea kvm_gdt + 3*8, %edi
|
|
mov %eax, (%edi)
|
|
mov %ebx, 4(%edi)
|
|
mov $3 * 8, %eax
|
|
mov %ax, %ss
|
|
lea kvm_stack_top, %esp
|
|
|
|
/* Create a TSS descriptor in the 5th GDT slot */
|
|
lea kvm_tss, %edx
|
|
movl %edx, %ebx
|
|
andl $0xff000000, %ebx
|
|
movl %edx, %eax
|
|
shr $16, %eax
|
|
movb %al, %bl
|
|
orl $0x408900, %ebx /* flags + access bits */
|
|
|
|
movl %edx, %eax
|
|
movl $.Ltss_end - kvm_tss - 1, %edx
|
|
shl $16, %eax
|
|
movw %dx, %ax
|
|
andl $0xf0000, %edx
|
|
orl %edx, %ebx
|
|
|
|
lea kvm_gdt + 4*8, %edi
|
|
mov %eax, (%edi)
|
|
mov %ebx, 4(%edi)
|
|
mov $4 * 8, %ax
|
|
ltr %ax
|
|
|
|
/* Configure and enable interrupts */
|
|
call kvm_init_interrupts
|
|
lidt kvm_idt_desc
|
|
sti
|
|
|
|
/*
|
|
* Do just enough of initialization to get to a working
|
|
* -ffreestanding environment and call tst_main(void).
|
|
*/
|
|
lea __preinit_array_start, %edi
|
|
lea __preinit_array_end, %esi
|
|
1:
|
|
cmp %edi, %esi
|
|
je 2f
|
|
call *(%edi)
|
|
add $4, %edi
|
|
jmp 1b
|
|
2:
|
|
|
|
lea __init_array_start, %edi
|
|
lea __init_array_end, %esi
|
|
1:
|
|
cmp %edi, %esi
|
|
je 2f
|
|
call *(%edi)
|
|
add $4, %edi
|
|
jmp 1b
|
|
2:
|
|
call main
|
|
jmp kvm_exit
|
|
|
|
.global kvm_read_cregs
|
|
kvm_read_cregs:
|
|
push %edi
|
|
mov 8(%esp), %edi
|
|
mov %cr0, %eax
|
|
mov %eax, (%edi)
|
|
mov %cr2, %eax
|
|
mov %eax, 4(%edi)
|
|
mov %cr3, %eax
|
|
mov %eax, 8(%edi)
|
|
mov %cr4, %eax
|
|
mov %eax, 12(%edi)
|
|
pop %edi
|
|
ret
|
|
|
|
handle_interrupt:
|
|
/* save CPU state */
|
|
push %ebp
|
|
mov %esp, %ebp
|
|
addl $12, %ebp
|
|
pushal
|
|
|
|
/* call handler */
|
|
push -4(%ebp)
|
|
push -8(%ebp)
|
|
push %ebp
|
|
cld
|
|
call tst_handle_interrupt
|
|
addl $12, %esp
|
|
popal
|
|
pop %ebp
|
|
addl $8, %esp
|
|
iret
|
|
|
|
.macro create_intr_handler vector:req padargs=0
|
|
.if \padargs
|
|
pushl $0 /* push dummy error code */
|
|
.endif
|
|
pushl $\vector
|
|
jmp handle_interrupt
|
|
.endm
|
|
|
|
.global kvm_handle_zerodiv
|
|
kvm_handle_zerodiv:
|
|
create_intr_handler 0, padargs=1
|
|
|
|
.global kvm_handle_debug
|
|
kvm_handle_debug:
|
|
create_intr_handler 1, padargs=1
|
|
|
|
.global kvm_handle_nmi
|
|
kvm_handle_nmi:
|
|
create_intr_handler 2, padargs=1
|
|
|
|
.global kvm_handle_breakpoint
|
|
kvm_handle_breakpoint:
|
|
create_intr_handler 3, padargs=1
|
|
|
|
.global kvm_handle_overflow
|
|
kvm_handle_overflow:
|
|
create_intr_handler 4, padargs=1
|
|
|
|
.global kvm_handle_bound_range_exc
|
|
kvm_handle_bound_range_exc:
|
|
create_intr_handler 5, padargs=1
|
|
|
|
.global kvm_handle_bad_opcode
|
|
kvm_handle_bad_opcode:
|
|
create_intr_handler 6, padargs=1
|
|
|
|
.global kvm_handle_device_error
|
|
kvm_handle_device_error:
|
|
create_intr_handler 7, padargs=1
|
|
|
|
.global kvm_handle_double_fault
|
|
kvm_handle_double_fault:
|
|
create_intr_handler 8
|
|
|
|
.global kvm_handle_invalid_tss
|
|
kvm_handle_invalid_tss:
|
|
create_intr_handler 10
|
|
|
|
.global kvm_handle_segfault
|
|
kvm_handle_segfault:
|
|
create_intr_handler 11
|
|
|
|
.global kvm_handle_stack_fault
|
|
kvm_handle_stack_fault:
|
|
create_intr_handler 12
|
|
|
|
.global kvm_handle_gpf
|
|
kvm_handle_gpf:
|
|
create_intr_handler 13
|
|
|
|
.global kvm_handle_page_fault
|
|
kvm_handle_page_fault:
|
|
create_intr_handler 14
|
|
|
|
.global kvm_handle_fpu_error
|
|
kvm_handle_fpu_error:
|
|
create_intr_handler 16, padargs=1
|
|
|
|
.global kvm_handle_alignment_error
|
|
kvm_handle_alignment_error:
|
|
create_intr_handler 17
|
|
|
|
.global kvm_handle_machine_check
|
|
kvm_handle_machine_check:
|
|
create_intr_handler 18, padargs=1
|
|
|
|
.global kvm_handle_simd_error
|
|
kvm_handle_simd_error:
|
|
create_intr_handler 19, padargs=1
|
|
|
|
.global kvm_handle_virt_error
|
|
kvm_handle_virt_error:
|
|
create_intr_handler 20, padargs=1
|
|
|
|
.global kvm_handle_cpe
|
|
kvm_handle_cpe:
|
|
create_intr_handler 21
|
|
|
|
.global kvm_handle_hv_injection
|
|
kvm_handle_hv_injection:
|
|
create_intr_handler 28, padargs=1
|
|
|
|
.global kvm_handle_vmm_comm
|
|
kvm_handle_vmm_comm:
|
|
create_intr_handler 29
|
|
|
|
.global kvm_handle_security_error
|
|
kvm_handle_security_error:
|
|
create_intr_handler 30
|
|
|
|
.global kvm_handle_bad_exception
|
|
kvm_handle_bad_exception:
|
|
create_intr_handler -1, padargs=1
|
|
|
|
.global kvm_exit
|
|
kvm_exit:
|
|
movl $RESULT_ADDRESS, %edi
|
|
movl $KVM_TEXIT, (%edi)
|
|
hlt
|
|
jmp kvm_exit
|
|
|
|
.global kvm_yield
|
|
kvm_yield:
|
|
hlt
|
|
ret
|
|
|
|
|
|
.section .bss.pgtables, "aw", @nobits
|
|
.global kvm_pagetable
|
|
kvm_pagetable:
|
|
.skip 4096
|
|
|
|
kvm_pgtable_l2:
|
|
.skip 1024 * 4096
|
|
|
|
.section .bss.stack, "aw", @nobits
|
|
.global kvm_stack_bottom
|
|
kvm_stack_bottom:
|
|
.skip 2 * 4096
|
|
.global kvm_stack_top
|
|
kvm_stack_top:
|
|
|
|
.section .bss.tss
|
|
.global kvm_tss
|
|
kvm_tss:
|
|
.skip 0x6C
|
|
.Ltss_end:
|
|
|
|
.section .bss
|
|
.align 8
|
|
.global kvm_idt
|
|
kvm_idt:
|
|
.skip 8 * 256
|
|
.Lidt_end:
|
|
|
|
.section .data
|
|
.align 8
|
|
.global kvm_idt_desc
|
|
kvm_idt_desc:
|
|
.2byte .Lidt_end - kvm_idt - 1
|
|
.4byte kvm_idt
|