acrn-hypervisor/hypervisor/debug/dump.c
Jason Chen CJ 2d469a5e5f modularization: hypervisor initilization component
hypervisor initilization component triggered by boot component,
and it calls different components initilization functions from
the highest layer.

this patch added init.c and move reorged cpu init functions into
it, keep hardware management functions in cpu.c but move other
components' init function into init.c.

the hypervisor initilization components will call:
- init_cpu_pre
- init_cpu_post
- init_bsp
- init_debug_pre
- init_debug_post
- init_guest
- init_passthru
- enter_guest_mode

the hypervisor initilization component include files:
arch/x86/init.c
include/arch/x86/init.h

this component is higest layer, so there is no reverse dependencies for it.

v2:
- separate into 2 patches, 1 for reorg, 1 for pure move.

Tracked-On: #1842
Signed-off-by: Jason Chen CJ <jason.cj.chen@intel.com>
Acked-by: Xu, Anthony <anthony.xu@intel.com>
2018-12-14 08:56:15 +08:00

302 lines
8.9 KiB
C

/*
* Copyright (C) 2018 Intel Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <hypervisor.h>
#include <init.h>
#define CALL_TRACE_HIERARCHY_MAX 20U
#define DUMP_STACK_SIZE 0x200U
/*
* readable exception descriptors.
*/
static const char *const excp_names[32] = {
[0] = "Divide Error",
[1] = "RESERVED",
[2] = "NMI",
[3] = "Breakpoint",
[4] = "Overflow",
[5] = "BOUND range exceeded",
[6] = "Invalid Opcode",
[7] = "Device Not Available",
[8] = "Double Fault",
[9] = "Coprocessor Segment Overrun",
[10] = "Invalid TSS",
[11] = "Segment Not Present",
[12] = "Stack Segment Fault",
[13] = "General Protection",
[14] = "Page Fault",
[15] = "Intel Reserved",
[16] = "x87 FPU Floating Point Error",
[17] = "Alignment Check",
[18] = "Machine Check",
[19] = "SIMD Floating Point Exception",
[20] = "Virtualization Exception",
[21] = "Intel Reserved",
[22] = "Intel Reserved",
[23] = "Intel Reserved",
[24] = "Intel Reserved",
[25] = "Intel Reserved",
[26] = "Intel Reserved",
[27] = "Intel Reserved",
[28] = "Intel Reserved",
[29] = "Intel Reserved",
[30] = "Intel Reserved",
[31] = "Intel Reserved"
};
/*
* Global variable for save registers on exception.
* don't change crash_ctx to static.
* crash_ctx is for offline analysis when system crashed, not for runtime usage.
* as crash_ctx is only be set without being read, compiler will regard
* crash_ctx as an useless variable if it is set to static, and will not
* generate code for it.
*/
struct intr_excp_ctx *crash_ctx;
static void dump_guest_reg(struct acrn_vcpu *vcpu)
{
printf("\n\n================================================");
printf("================================\n\n");
printf("Guest Registers:\r\n");
printf("= VM ID %d ==== vCPU ID %hu === pCPU ID %d ===="
"world %d =============\r\n",
vcpu->vm->vm_id, vcpu->vcpu_id, vcpu->pcpu_id,
vcpu->arch.cur_context);
printf("= RIP=0x%016llx RSP=0x%016llx "
"RFLAGS=0x%016llx\r\n",
vcpu_get_rip(vcpu),
vcpu_get_gpreg(vcpu, CPU_REG_RSP),
vcpu_get_rflags(vcpu));
printf("= CR0=0x%016llx CR2=0x%016llx "
" CR3=0x%016llx\r\n",
vcpu_get_cr0(vcpu),
vcpu_get_cr2(vcpu),
exec_vmread(VMX_GUEST_CR3));
printf("= RAX=0x%016llx RBX=0x%016llx "
"RCX=0x%016llx\r\n",
vcpu_get_gpreg(vcpu, CPU_REG_RAX),
vcpu_get_gpreg(vcpu, CPU_REG_RBX),
vcpu_get_gpreg(vcpu, CPU_REG_RCX));
printf("= RDX=0x%016llx RDI=0x%016llx "
"RSI=0x%016llx\r\n",
vcpu_get_gpreg(vcpu, CPU_REG_RDX),
vcpu_get_gpreg(vcpu, CPU_REG_RDI),
vcpu_get_gpreg(vcpu, CPU_REG_RSI));
printf("= RBP=0x%016llx R8=0x%016llx "
"R9=0x%016llx\r\n",
vcpu_get_gpreg(vcpu, CPU_REG_RBP),
vcpu_get_gpreg(vcpu, CPU_REG_R8),
vcpu_get_gpreg(vcpu, CPU_REG_R9));
printf("= R10=0x%016llx R11=0x%016llx "
"R12=0x%016llx\r\n",
vcpu_get_gpreg(vcpu, CPU_REG_R10),
vcpu_get_gpreg(vcpu, CPU_REG_R11),
vcpu_get_gpreg(vcpu, CPU_REG_R12));
printf("= R13=0x%016llx R14=0x%016llx "
"R15=0x%016llx\r\n",
vcpu_get_gpreg(vcpu, CPU_REG_R13),
vcpu_get_gpreg(vcpu, CPU_REG_R14),
vcpu_get_gpreg(vcpu, CPU_REG_R15));
printf("\r\n");
}
static void dump_guest_stack(struct acrn_vcpu *vcpu)
{
uint32_t i;
uint64_t tmp[DUMP_STACK_SIZE], fault_addr;
uint32_t err_code = 0U;
if (copy_from_gva(vcpu, tmp, vcpu_get_gpreg(vcpu, CPU_REG_RSP),
DUMP_STACK_SIZE, &err_code, &fault_addr) < 0) {
printf("\r\nUnabled to Copy Guest Stack:\r\n");
return;
}
printf("\r\nGuest Stack:\r\n");
printf("Dump stack for vcpu %hu, from gva 0x%016llx\r\n",
vcpu->vcpu_id, vcpu_get_gpreg(vcpu, CPU_REG_RSP));
for (i = 0U; i < (DUMP_STACK_SIZE >> 5U); i++) {
printf("guest_rsp(0x%llx): 0x%016llx 0x%016llx "
"0x%016llx 0x%016llx\r\n",
(vcpu_get_gpreg(vcpu, CPU_REG_RSP)+(i*32U)),
tmp[i*4], tmp[(i*4)+1],
tmp[(i*4)+2], tmp[(i*4)+3]);
}
printf("\r\n");
}
static void show_guest_call_trace(struct acrn_vcpu *vcpu)
{
uint64_t bp;
uint64_t count = 0UL;
int32_t err;
uint32_t err_code;
bp = vcpu_get_gpreg(vcpu, CPU_REG_RBP);
printf("Guest Call Trace: **************************************\r\n");
printf("Maybe the call trace is not accurate, pls check stack!!\r\n");
/* if enable compiler option(no-omit-frame-pointer) the stack layout
* should be like this when call a function for x86_64
*
* | |
* rbp+8 | return address |
* rbp | rbp | push rbp
* | | mov rsp rbp
*
* rsp | |
*
* try to print out call trace,here can not check if the rbp is valid
* if the address is invalid, it will cause hv page fault
* then halt system */
while ((count < CALL_TRACE_HIERARCHY_MAX) && (bp != 0UL)) {
uint64_t parent_bp = 0UL, fault_addr;
err_code = 0U;
err = copy_from_gva(vcpu, &parent_bp, bp, sizeof(parent_bp),
&err_code, &fault_addr);
if (err < 0) {
printf("\r\nUnabled to get Guest parent BP\r\n");
return;
}
printf("BP_GVA(0x%016llx) RIP=0x%016llx\r\n", bp, parent_bp);
/* Get previous rbp*/
bp = parent_bp;
count++;
}
printf("\r\n");
}
static void dump_guest_context(uint16_t pcpu_id)
{
struct acrn_vcpu *vcpu;
vcpu = per_cpu(vcpu, pcpu_id);
if (vcpu != NULL) {
dump_guest_reg(vcpu);
dump_guest_stack(vcpu);
show_guest_call_trace(vcpu);
}
}
static void show_host_call_trace(uint64_t rsp, uint64_t rbp_arg, uint16_t pcpu_id)
{
uint64_t rbp = rbp_arg;
uint32_t i = 0U;
uint32_t cb_hierarchy = 0U;
uint64_t *sp = (uint64_t *)rsp;
printf("\r\nHost Stack: CPU_ID = %hu\r\n", pcpu_id);
for (i = 0U; i < (DUMP_STACK_SIZE >> 5U); i++) {
printf("addr(0x%llx) 0x%016llx 0x%016llx 0x%016llx "
"0x%016llx\r\n", (rsp + (i * 32U)), sp[i * 4U],
sp[(i * 4U) + 1U], sp[(i * 4U) + 2U],
sp[(i * 4U) + 3U]);
}
printf("\r\n");
printf("Host Call Trace:\r\n");
if ((rsp >
(uint64_t)&per_cpu(stack, pcpu_id)[CONFIG_STACK_SIZE - 1])
|| (rsp < (uint64_t)&per_cpu(stack, pcpu_id)[0])) {
return;
}
/* if enable compiler option(no-omit-frame-pointer) the stack layout
* should be like this when call a function for x86_64
*
* | |
* rbp+8 | return address |
* rbp | rbp | push rbp
* | | mov rsp rbp
*
* rsp | |
*
*
* if the address is invalid, it will cause hv page fault
* then halt system */
while ((rbp <=
(uint64_t)&per_cpu(stack, pcpu_id)[CONFIG_STACK_SIZE - 1])
&& (rbp >= (uint64_t)&per_cpu(stack, pcpu_id)[0])
&& (cb_hierarchy < CALL_TRACE_HIERARCHY_MAX)) {
printf("----> 0x%016llx\r\n",
*(uint64_t *)(rbp + sizeof(uint64_t)));
if (*(uint64_t *)(rbp + (2U*sizeof(uint64_t)))
== SP_BOTTOM_MAGIC) {
break;
}
rbp = *(uint64_t *)rbp;
cb_hierarchy++;
}
printf("\r\n");
}
void asm_assert(int32_t line, const char *file, const char *txt)
{
uint16_t pcpu_id = get_cpu_id();
uint64_t rsp = cpu_rsp_get();
uint64_t rbp = cpu_rbp_get();
printf("Assertion failed in file %s,line %d : %s",
file, line, txt);
show_host_call_trace(rsp, rbp, pcpu_id);
dump_guest_context(pcpu_id);
do {
pause_cpu();
} while (1);
}
void dump_intr_excp_frame(const struct intr_excp_ctx *ctx)
{
const char *name = "Not defined";
printf("\n\n================================================");
printf("================================\n=\n");
if (ctx->vector < 0x20UL) {
name = excp_names[ctx->vector];
printf("= Unhandled exception: %d (%s)\n", ctx->vector, name);
}
/* Dump host register*/
printf("\r\nHost Registers:\r\n");
printf("= Vector=0x%016llX RIP=0x%016llX\n",
ctx->vector, ctx->rip);
printf("= RAX=0x%016llX RBX=0x%016llX RCX=0x%016llX\n",
ctx->gp_regs.rax, ctx->gp_regs.rbx, ctx->gp_regs.rcx);
printf("= RDX=0x%016llX RDI=0x%016llX RSI=0x%016llX\n",
ctx->gp_regs.rdx, ctx->gp_regs.rdi, ctx->gp_regs.rsi);
printf("= RSP=0x%016llX RBP=0x%016llX RBX=0x%016llX\n",
ctx->gp_regs.rsp, ctx->gp_regs.rbp, ctx->gp_regs.rbx);
printf("= R8=0x%016llX R9=0x%016llX R10=0x%016llX\n",
ctx->gp_regs.r8, ctx->gp_regs.r9, ctx->gp_regs.r10);
printf("= R11=0x%016llX R12=0x%016llX R13=0x%016llX\n",
ctx->gp_regs.r11, ctx->gp_regs.r12, ctx->gp_regs.r13);
printf("= RFLAGS=0x%016llX R14=0x%016llX R15=0x%016llX\n",
ctx->rflags, ctx->gp_regs.r14, ctx->gp_regs.r15);
printf("= ERRCODE=0x%016llX CS=0x%016llX SS=0x%016llX\n",
ctx->error_code, ctx->cs, ctx->ss);
printf("\r\n");
printf("=====================================================");
printf("===========================\n");
}
void dump_exception(struct intr_excp_ctx *ctx, uint16_t pcpu_id)
{
/* Dump host context */
dump_intr_excp_frame(ctx);
/* Show host stack */
show_host_call_trace(ctx->gp_regs.rsp, ctx->gp_regs.rbp, pcpu_id);
/* Dump guest context */
dump_guest_context(pcpu_id);
/* Save registers*/
crash_ctx = ctx;
cache_flush_invalidate_all();
}