crash/xen_hyper.c
Juergen Gross 97269209aa xen: adjust to new scheduler structures
There has been a significant modification regarding scheduler data in
the Xen hypervisor (Xen commit d62fefa4d459). Adapt to new structures
and removed fields.

Note that this is only the bare minimum to not let crash error out when
opening a vmcore in Xen mode with a recent Xen version.

Signed-off-by: Juergen Gross <jgross@suse.com>
2023-03-17 13:12:48 +09:00

2205 lines
63 KiB
C

/*
* xen_hyper.c
*
* Portions Copyright (C) 2006-2007 Fujitsu Limited
* Portions Copyright (C) 2006-2007 VA Linux Systems Japan K.K.
*
* Authors: Itsuro Oda <oda@valinux.co.jp>
* Fumihiko Kakuma <kakuma@valinux.co.jp>
*
* This file is part of Xencrash.
*
* Xencrash is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Xencrash is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Xencrash; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "defs.h"
#ifdef XEN_HYPERVISOR_ARCH
#include "xen_hyper_defs.h"
static void xen_hyper_schedule_init(void);
/*
* Do initialization for Xen Hyper system here.
*/
void
xen_hyper_init(void)
{
char *buf;
#if defined(X86) || defined(X86_64)
long member_offset;
#endif
#ifdef X86_64
xht->xen_virt_start = symbol_value("start");
/*
* Xen virtual mapping is aligned to 1 GiB boundary.
* Image starts no more than 1 GiB below
* beginning of virtual address space.
*/
xht->xen_virt_start &= 0xffffffffc0000000;
#endif
if (machine_type("X86_64") &&
symbol_exists("xen_phys_start") && !xen_phys_start())
error(WARNING,
"This hypervisor is relocatable; if initialization fails below, try\n"
" using the \"--xen_phys_start <address>\" command line option.\n\n");
if (symbol_exists("crashing_cpu")) {
get_symbol_data("crashing_cpu", sizeof(xht->crashing_cpu),
&xht->crashing_cpu);
} else {
xht->crashing_cpu = XEN_HYPER_PCPU_ID_INVALID;
}
machdep->get_smp_cpus();
machdep->memory_size();
if (symbol_exists("__per_cpu_offset")) {
xht->flags |= XEN_HYPER_SMP;
if((xht->__per_cpu_offset = malloc(sizeof(ulong) * XEN_HYPER_MAX_CPUS())) == NULL) {
error(FATAL, "cannot malloc __per_cpu_offset space.\n");
}
if (!readmem(symbol_value("__per_cpu_offset"), KVADDR,
xht->__per_cpu_offset, sizeof(ulong) * XEN_HYPER_MAX_CPUS(),
"__per_cpu_offset", RETURN_ON_ERROR)) {
error(FATAL, "cannot read __per_cpu_offset.\n");
}
}
#if defined(X86) || defined(X86_64)
if (symbol_exists("__per_cpu_shift")) {
xht->percpu_shift = (int)symbol_value("__per_cpu_shift");
} else if (xen_major_version() >= 3 && xen_minor_version() >= 3) {
xht->percpu_shift = 13;
} else {
xht->percpu_shift = 12;
}
member_offset = MEMBER_OFFSET("cpuinfo_x86", "x86_model_id");
buf = GETBUF(XEN_HYPER_SIZE(cpuinfo_x86));
if (xen_hyper_test_pcpu_id(XEN_HYPER_CRASHING_CPU())) {
xen_hyper_x86_fill_cpu_data(XEN_HYPER_CRASHING_CPU(), buf);
} else {
xen_hyper_x86_fill_cpu_data(xht->cpu_idxs[0], buf);
}
strncpy(xht->utsname.machine, (char *)(buf + member_offset),
sizeof(xht->utsname.machine)-1);
FREEBUF(buf);
#elif defined(IA64)
buf = GETBUF(XEN_HYPER_SIZE(cpuinfo_ia64));
if (xen_hyper_test_pcpu_id(XEN_HYPER_CRASHING_CPU())) {
xen_hyper_ia64_fill_cpu_data(XEN_HYPER_CRASHING_CPU(), buf);
} else {
xen_hyper_ia64_fill_cpu_data(xht->cpu_idxs[0], buf);
}
strncpy(xht->utsname.machine, (char *)(buf + XEN_HYPER_OFFSET(cpuinfo_ia64_vendor)),
sizeof(xht->utsname.machine)-1);
FREEBUF(buf);
#endif
#ifndef IA64
XEN_HYPER_STRUCT_SIZE_INIT(note_buf_t, "note_buf_t");
XEN_HYPER_STRUCT_SIZE_INIT(crash_note_t, "crash_note_t");
XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_t_core, "crash_note_t", "core");
XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_t_xen, "crash_note_t", "xen");
XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_t_xen_regs, "crash_note_t", "xen_regs");
XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_t_xen_info, "crash_note_t", "xen_info");
XEN_HYPER_STRUCT_SIZE_INIT(crash_note_core_t, "crash_note_core_t");
XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_core_t_note, "crash_note_core_t", "note");
XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_core_t_desc, "crash_note_core_t", "desc");
XEN_HYPER_STRUCT_SIZE_INIT(crash_note_xen_t, "crash_note_xen_t");
XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_xen_t_note, "crash_note_xen_t", "note");
XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_xen_t_desc, "crash_note_xen_t", "desc");
XEN_HYPER_STRUCT_SIZE_INIT(crash_note_xen_core_t, "crash_note_xen_core_t");
XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_xen_core_t_note, "crash_note_xen_core_t", "note");
XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_xen_core_t_desc, "crash_note_xen_core_t", "desc");
XEN_HYPER_STRUCT_SIZE_INIT(crash_note_xen_info_t, "crash_note_xen_info_t");
XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_xen_info_t_note, "crash_note_xen_info_t", "note");
XEN_HYPER_MEMBER_OFFSET_INIT(crash_note_xen_info_t_desc, "crash_note_xen_info_t", "desc");
XEN_HYPER_STRUCT_SIZE_INIT(crash_xen_core_t, "crash_xen_core_t");
XEN_HYPER_STRUCT_SIZE_INIT(crash_xen_info_t, "crash_xen_info_t");
XEN_HYPER_STRUCT_SIZE_INIT(xen_crash_xen_regs_t, "xen_crash_xen_regs_t");
XEN_HYPER_STRUCT_SIZE_INIT(ELF_Prstatus,"ELF_Prstatus");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_info, "ELF_Prstatus", "pr_info");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_cursig, "ELF_Prstatus", "pr_cursig");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_sigpend, "ELF_Prstatus", "pr_sigpend");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_sighold, "ELF_Prstatus", "pr_sighold");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_pid, "ELF_Prstatus", "pr_pid");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_ppid, "ELF_Prstatus", "pr_ppid");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_pgrp, "ELF_Prstatus", "pr_pgrp");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_sid, "ELF_Prstatus", "pr_sid");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_utime, "ELF_Prstatus", "pr_utime");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_stime, "ELF_Prstatus", "pr_stime");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_cutime, "ELF_Prstatus", "pr_cutime");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_cstime, "ELF_Prstatus", "pr_cstime");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_reg, "ELF_Prstatus", "pr_reg");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Prstatus_pr_fpvalid, "ELF_Prstatus", "pr_fpvalid");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Timeval_tv_sec, "ELF_Timeval", "tv_sec");
XEN_HYPER_MEMBER_OFFSET_INIT(ELF_Timeval_tv_usec, "ELF_Timeval", "tv_usec");
XEN_HYPER_STRUCT_SIZE_INIT(ELF_Signifo,"ELF_Signifo");
XEN_HYPER_STRUCT_SIZE_INIT(ELF_Gregset,"ELF_Gregset");
XEN_HYPER_STRUCT_SIZE_INIT(ELF_Timeval,"ELF_Timeval");
#endif
XEN_HYPER_STRUCT_SIZE_INIT(domain, "domain");
XEN_HYPER_STRUCT_SIZE_INIT(vcpu, "vcpu");
#ifndef IA64
XEN_HYPER_STRUCT_SIZE_INIT(cpu_info, "cpu_info");
#endif
XEN_HYPER_STRUCT_SIZE_INIT(cpu_user_regs, "cpu_user_regs");
xht->idle_vcpu_size = get_array_length("idle_vcpu", NULL, 0);
xht->idle_vcpu_array = (ulong *)malloc(xht->idle_vcpu_size * sizeof(ulong));
if (xht->idle_vcpu_array == NULL) {
error(FATAL, "cannot malloc idle_vcpu_array space.\n");
}
if (!readmem(symbol_value("idle_vcpu"), KVADDR, xht->idle_vcpu_array,
xht->idle_vcpu_size * sizeof(ulong), "idle_vcpu_array",
RETURN_ON_ERROR)) {
error(FATAL, "cannot read idle_vcpu array.\n");
}
/*
* Do some initialization.
*/
#ifndef IA64
xen_hyper_dumpinfo_init();
#endif
xhmachdep->pcpu_init();
xen_hyper_domain_init();
xen_hyper_vcpu_init();
xen_hyper_misc_init();
/*
* xen_hyper_post_init() have to be called after all initialize
* functions finished.
*/
xen_hyper_post_init();
}
/*
* Do initialization for Domain of Xen Hyper system here.
*/
void
xen_hyper_domain_init(void)
{
XEN_HYPER_MEMBER_OFFSET_INIT(domain_domain_id, "domain", "domain_id");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_tot_pages, "domain", "tot_pages");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_max_pages, "domain", "max_pages");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_xenheap_pages, "domain", "xenheap_pages");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_shared_info, "domain", "shared_info");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_sched_priv, "domain", "sched_priv");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_next_in_list, "domain", "next_in_list");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_domain_flags, "domain", "domain_flags");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_evtchn, "domain", "evtchn");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_hvm, "domain", "is_hvm");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_guest_type, "domain", "guest_type");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_privileged, "domain", "is_privileged");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_debugger_attached, "domain", "debugger_attached");
/*
* Will be removed in Xen 4.4 (hg ae9b223a675d),
* need to check that with XEN_HYPER_VALID_MEMBER() before using
*/
XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_polling, "domain", "is_polling");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_dying, "domain", "is_dying");
/*
* With Xen 4.2.5 is_paused_by_controller changed to
* controller_pause_count.
*/
XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_paused_by_controller, "domain", "is_paused_by_controller");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_controller_pause_count, "domain", "controller_pause_count");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_shutting_down, "domain", "is_shutting_down");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_is_shut_down, "domain", "is_shut_down");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_vcpu, "domain", "vcpu");
XEN_HYPER_MEMBER_SIZE_INIT(domain_vcpu, "domain", "vcpu");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_max_vcpus, "domain", "max_vcpus");
XEN_HYPER_MEMBER_OFFSET_INIT(domain_arch, "domain", "arch");
XEN_HYPER_STRUCT_SIZE_INIT(arch_shared_info, "arch_shared_info");
XEN_HYPER_MEMBER_OFFSET_INIT(arch_shared_info_max_pfn, "arch_shared_info", "max_pfn");
XEN_HYPER_MEMBER_OFFSET_INIT(arch_shared_info_pfn_to_mfn_frame_list_list, "arch_shared_info", "pfn_to_mfn_frame_list_list");
XEN_HYPER_MEMBER_OFFSET_INIT(arch_shared_info_nmi_reason, "arch_shared_info", "nmi_reason");
XEN_HYPER_STRUCT_SIZE_INIT(shared_info, "shared_info");
XEN_HYPER_MEMBER_OFFSET_INIT(shared_info_vcpu_info, "shared_info", "vcpu_info");
XEN_HYPER_MEMBER_OFFSET_INIT(shared_info_evtchn_pending, "shared_info", "evtchn_pending");
XEN_HYPER_MEMBER_OFFSET_INIT(shared_info_evtchn_mask, "shared_info", "evtchn_mask");
XEN_HYPER_MEMBER_OFFSET_INIT(shared_info_arch, "shared_info", "arch");
XEN_HYPER_STRUCT_SIZE_INIT(arch_domain, "arch_domain");
#ifdef IA64
XEN_HYPER_MEMBER_OFFSET_INIT(arch_domain_mm, "arch_domain", "mm");
XEN_HYPER_STRUCT_SIZE_INIT(mm_struct, "mm_struct");
XEN_HYPER_MEMBER_OFFSET_INIT(mm_struct_pgd, "mm_struct", "pgd");
#endif
if((xhdt->domain_struct = malloc(XEN_HYPER_SIZE(domain))) == NULL) {
error(FATAL, "cannot malloc domain struct space.\n");
}
if((xhdt->domain_struct_verify = malloc(XEN_HYPER_SIZE(domain))) == NULL) {
error(FATAL, "cannot malloc domain struct space to verification.\n");
}
xen_hyper_refresh_domain_context_space();
xhdt->flags |= XEN_HYPER_DOMAIN_F_INIT;
}
/*
* Do initialization for vcpu of Xen Hyper system here.
*/
void
xen_hyper_vcpu_init(void)
{
XEN_HYPER_STRUCT_SIZE_INIT(timer, "timer");
XEN_HYPER_MEMBER_OFFSET_INIT(timer_expires, "timer", "expires");
XEN_HYPER_MEMBER_OFFSET_INIT(timer_cpu, "timer", "cpu");
XEN_HYPER_MEMBER_OFFSET_INIT(timer_function, "timer", "function");
XEN_HYPER_MEMBER_OFFSET_INIT(timer_data, "timer", "data");
XEN_HYPER_MEMBER_OFFSET_INIT(timer_heap_offset, "timer", "heap_offset");
XEN_HYPER_MEMBER_OFFSET_INIT(timer_killed, "timer", "killed");
XEN_HYPER_STRUCT_SIZE_INIT(vcpu_runstate_info, "vcpu_runstate_info");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_runstate_info_state, "vcpu_runstate_info", "state");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_runstate_info_state_entry_time, "vcpu_runstate_info", "state_entry_time");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_runstate_info_time, "vcpu_runstate_info", "time");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_vcpu_id, "vcpu", "vcpu_id");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_processor, "vcpu", "processor");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_vcpu_info, "vcpu", "vcpu_info");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_domain, "vcpu", "domain");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_next_in_list, "vcpu", "next_in_list");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_timer, "vcpu", "timer");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_sleep_tick, "vcpu", "sleep_tick");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_poll_timer, "vcpu", "poll_timer");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_sched_priv, "vcpu", "sched_priv");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_runstate, "vcpu", "runstate");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_runstate_guest, "vcpu", "runstate_guest");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_vcpu_flags, "vcpu", "vcpu_flags");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_pause_count, "vcpu", "pause_count");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_virq_to_evtchn, "vcpu", "virq_to_evtchn");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_cpu_affinity, "vcpu", "cpu_affinity");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_nmi_addr, "vcpu", "nmi_addr");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_vcpu_dirty_cpumask, "vcpu", "vcpu_dirty_cpumask");
XEN_HYPER_MEMBER_OFFSET_INIT(vcpu_arch, "vcpu", "arch");
#ifdef IA64
XEN_HYPER_ASSIGN_OFFSET(vcpu_thread_ksp) =
MEMBER_OFFSET("vcpu", "arch") + MEMBER_OFFSET("arch_vcpu", "_thread") +
MEMBER_OFFSET("thread_struct", "ksp");
#endif
if((xhvct->vcpu_struct = malloc(XEN_HYPER_SIZE(vcpu))) == NULL) {
error(FATAL, "cannot malloc vcpu struct space.\n");
}
if((xhvct->vcpu_struct_verify = malloc(XEN_HYPER_SIZE(vcpu))) == NULL) {
error(FATAL, "cannot malloc vcpu struct space to verification.\n");
}
xen_hyper_refresh_vcpu_context_space();
xhvct->flags |= XEN_HYPER_VCPU_F_INIT;
xhvct->idle_vcpu = symbol_value("idle_vcpu");
}
/*
* Do initialization for pcpu of Xen Hyper system here.
*/
#if defined(X86) || defined(X86_64)
void
xen_hyper_x86_pcpu_init(void)
{
ulong cpu_info;
ulong init_tss_base, init_tss, stack_base = 0;
ulong sp;
struct xen_hyper_pcpu_context *pcc;
char *buf, *bp;
int i, cpuid;
int flag;
XEN_HYPER_MEMBER_OFFSET_INIT(cpu_info_guest_cpu_user_regs, "cpu_info", "guest_cpu_user_regs");
XEN_HYPER_MEMBER_OFFSET_INIT(cpu_info_processor_id, "cpu_info", "processor_id");
XEN_HYPER_MEMBER_OFFSET_INIT(cpu_info_current_vcpu, "cpu_info", "current_vcpu");
if((xhpct->pcpu_struct = malloc(XEN_HYPER_SIZE(cpu_info))) == NULL) {
error(FATAL, "cannot malloc pcpu struct space.\n");
}
/* get physical cpu context */
xen_hyper_alloc_pcpu_context_space(XEN_HYPER_MAX_CPUS());
if (symbol_exists("stack_base")) {
stack_base = symbol_value("stack_base");
flag = 0;
} else if (symbol_exists("per_cpu__init_tss")) {
init_tss_base = symbol_value("per_cpu__init_tss");
flag = 1;
} else if (symbol_exists("per_cpu__tss_page")) {
init_tss_base = symbol_value("per_cpu__tss_page");
flag = 1;
} else {
init_tss_base = symbol_value("init_tss");
flag = 2;
}
if (flag)
buf = GETBUF(XEN_HYPER_SIZE(tss));
for_cpu_indexes(i, cpuid)
{
if (flag) {
if (flag == 1)
init_tss = xen_hyper_per_cpu(init_tss_base, cpuid);
else
init_tss = init_tss_base + XEN_HYPER_SIZE(tss) * cpuid;
readmem(init_tss, KVADDR, buf,
XEN_HYPER_SIZE(tss), "init_tss", FAULT_ON_ERROR);
if (machine_type("X86")) {
sp = ULONG(buf + XEN_HYPER_OFFSET(tss_esp0));
} else if (machine_type("X86_64")) {
sp = ULONG(buf + XEN_HYPER_OFFSET(tss_rsp0));
} else
sp = 0;
} else {
readmem(stack_base + sizeof(ulong) * cpuid, KVADDR, &sp,
sizeof(ulong), "stack_base", FAULT_ON_ERROR);
}
cpu_info = XEN_HYPER_GET_CPU_INFO(sp);
if (CRASHDEBUG(1)) {
fprintf(fp, "sp=%lx, cpu_info=%lx\n", sp, cpu_info);
}
if(!(bp = xen_hyper_read_pcpu(cpu_info))) {
error(FATAL, "cannot read cpu_info.\n");
}
pcc = &xhpct->context_array[cpuid];
xen_hyper_store_pcpu_context(pcc, cpu_info, bp);
if (flag)
xen_hyper_store_pcpu_context_tss(pcc, init_tss, buf);
}
if (flag)
FREEBUF(buf);
}
#elif defined(IA64)
void
xen_hyper_ia64_pcpu_init(void)
{
struct xen_hyper_pcpu_context *pcc;
int i, cpuid;
/* get physical cpu context */
xen_hyper_alloc_pcpu_context_space(XEN_HYPER_MAX_CPUS());
for_cpu_indexes(i, cpuid)
{
pcc = &xhpct->context_array[cpuid];
pcc->processor_id = cpuid;
}
}
#endif
/*
* Do initialization for some miscellaneous thing
* of Xen Hyper system here.
*/
void
xen_hyper_misc_init(void)
{
XEN_HYPER_STRUCT_SIZE_INIT(schedule_data, "schedule_data");
XEN_HYPER_STRUCT_SIZE_INIT(sched_resource, "sched_resource");
if (XEN_HYPER_VALID_SIZE(schedule_data)) {
XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_schedule_lock, "schedule_data", "schedule_lock");
XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_curr, "schedule_data", "curr");
if (MEMBER_EXISTS("schedule_data", "idle"))
XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_idle, "schedule_data", "idle");
XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_sched_priv, "schedule_data", "sched_priv");
XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_s_timer, "schedule_data", "s_timer");
XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_tick, "schedule_data", "tick");
} else if (XEN_HYPER_VALID_SIZE(sched_resource)) {
XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_schedule_lock, "sched_resource", "schedule_lock");
XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_curr, "sched_resource", "curr");
XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_sched_priv, "sched_resource", "sched_priv");
XEN_HYPER_MEMBER_OFFSET_INIT(schedule_data_s_timer, "sched_resource", "s_timer");
}
XEN_HYPER_STRUCT_SIZE_INIT(scheduler, "scheduler");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_name, "scheduler", "name");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_opt_name, "scheduler", "opt_name");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_sched_id, "scheduler", "sched_id");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_init, "scheduler", "init");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_tick, "scheduler", "tick");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_init_vcpu, "scheduler", "init_vcpu");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_destroy_domain, "scheduler", "destroy_domain");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_sleep, "scheduler", "sleep");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_wake, "scheduler", "wake");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_set_affinity, "scheduler", "set_affinity");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_do_schedule, "scheduler", "do_schedule");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_adjust, "scheduler", "adjust");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_dump_settings, "scheduler", "dump_settings");
XEN_HYPER_MEMBER_OFFSET_INIT(scheduler_dump_cpu_state, "scheduler", "dump_cpu_state");
xen_hyper_schedule_init();
}
/*
* Do initialization for scheduler of Xen Hyper system here.
*/
#define XEN_HYPER_SCHEDULER_NAME 1024
static int section_size(char *start_section, char *end_section)
{
ulong sp_start, sp_end;
sp_start = symbol_value(start_section);
sp_end = symbol_value(end_section);
return (sp_end - sp_start) / sizeof(long);
}
static void
xen_hyper_schedule_init(void)
{
ulong addr, opt_sched, schedulers, opt_name;
long scheduler_opt_name;
long *schedulers_buf;
int nr_schedulers;
struct xen_hyper_sched_context *schc;
long buf_size;
char *buf;
char opt_name_buf[XEN_HYPER_OPT_SCHED_SIZE];
int i, cpuid, flag;
char *sp_name;
/* get scheduler information */
if((xhscht->scheduler_struct =
malloc(XEN_HYPER_SIZE(scheduler))) == NULL) {
error(FATAL, "cannot malloc scheduler struct space.\n");
}
buf = GETBUF(XEN_HYPER_SCHEDULER_NAME);
scheduler_opt_name = XEN_HYPER_OFFSET(scheduler_opt_name);
if (symbol_exists("ops")) {
if (!readmem(symbol_value("ops") + scheduler_opt_name, KVADDR,
&opt_sched, sizeof(ulong), "ops.opt_name",
RETURN_ON_ERROR)) {
error(FATAL, "cannot read ops.opt_name.\n");
}
} else {
opt_sched = symbol_value("opt_sched");
}
if (!readmem(opt_sched, KVADDR, xhscht->opt_sched,
XEN_HYPER_OPT_SCHED_SIZE, "opt_sched,", RETURN_ON_ERROR)) {
error(FATAL, "cannot read opt_sched,.\n");
}
/* symbol exists since Xen 4.7 */
if (symbol_exists("__start_schedulers_array")) {
sp_name = "__start_schedulers_array";
nr_schedulers = section_size("__start_schedulers_array",
"__end_schedulers_array");
} else {
sp_name = "schedulers";
nr_schedulers = get_array_length("schedulers", 0, 0);
}
schedulers_buf = (long *)GETBUF(nr_schedulers * sizeof(long));
schedulers = symbol_value(sp_name);
addr = schedulers;
while (xhscht->name == NULL) {
if (!readmem(addr, KVADDR, schedulers_buf,
sizeof(long) * nr_schedulers,
"schedulers", RETURN_ON_ERROR)) {
error(FATAL, "cannot read schedulers.\n");
}
for (i = 0; i < nr_schedulers; i++) {
if (schedulers_buf[i] == 0) {
error(FATAL, "schedule data not found.\n");
}
if (!readmem(schedulers_buf[i], KVADDR,
xhscht->scheduler_struct, XEN_HYPER_SIZE(scheduler),
"scheduler", RETURN_ON_ERROR)) {
error(FATAL, "cannot read scheduler.\n");
}
opt_name = ULONG(xhscht->scheduler_struct +
scheduler_opt_name);
if (!readmem(opt_name, KVADDR, opt_name_buf,
XEN_HYPER_OPT_SCHED_SIZE, "opt_name", RETURN_ON_ERROR)) {
error(FATAL, "cannot read opt_name.\n");
}
if (strncmp(xhscht->opt_sched, opt_name_buf,
XEN_HYPER_OPT_SCHED_SIZE))
continue;
xhscht->scheduler = schedulers_buf[i];
xhscht->sched_id = INT(xhscht->scheduler_struct +
XEN_HYPER_OFFSET(scheduler_sched_id));
addr = ULONG(xhscht->scheduler_struct +
XEN_HYPER_OFFSET(scheduler_name));
if (!readmem(addr, KVADDR, buf, XEN_HYPER_SCHEDULER_NAME,
"scheduler_name", RETURN_ON_ERROR)) {
error(FATAL, "cannot read scheduler_name.\n");
}
if (strlen(buf) >= XEN_HYPER_SCHEDULER_NAME) {
error(FATAL, "cannot read scheduler_name.\n");
}
if((xhscht->name = malloc(strlen(buf) + 1)) == NULL) {
error(FATAL, "cannot malloc scheduler_name space.\n");
}
BZERO(xhscht->name, strlen(buf) + 1);
BCOPY(buf, xhscht->name, strlen(buf));
break;
}
addr += sizeof(long) * nr_schedulers;
}
FREEBUF(buf);
FREEBUF(schedulers_buf);
/* get schedule_data information */
if((xhscht->sched_context_array =
malloc(sizeof(struct xen_hyper_sched_context) * XEN_HYPER_MAX_CPUS())) == NULL) {
error(FATAL, "cannot malloc xen_hyper_sched_context struct space.\n");
}
BZERO(xhscht->sched_context_array,
sizeof(struct xen_hyper_sched_context) * XEN_HYPER_MAX_CPUS());
if (symbol_exists("per_cpu__sched_res")) {
addr = symbol_value("per_cpu__sched_res");
buf_size = XEN_HYPER_SIZE(sched_resource);
flag = 0;
} else if (symbol_exists("per_cpu__schedule_data")) {
addr = symbol_value("per_cpu__schedule_data");
buf_size = XEN_HYPER_SIZE(schedule_data);
flag = 1;
} else {
addr = symbol_value("schedule_data");
buf_size = XEN_HYPER_SIZE(schedule_data);
flag = 2;
}
buf = GETBUF(buf_size);
for_cpu_indexes(i, cpuid)
{
schc = &xhscht->sched_context_array[cpuid];
if (flag) {
if (flag == 1) {
schc->schedule_data =
xen_hyper_per_cpu(addr, i);
} else {
schc->schedule_data = addr +
XEN_HYPER_SIZE(schedule_data) * i;
}
readmem(schc->schedule_data,
KVADDR, buf, XEN_HYPER_SIZE(schedule_data),
"schedule_data", FAULT_ON_ERROR);
} else {
schc->sched_resource = xen_hyper_per_cpu(addr, i);
readmem(schc->sched_resource,
KVADDR, buf, XEN_HYPER_SIZE(sched_resource),
"sched_resource", FAULT_ON_ERROR);
}
schc->cpu_id = cpuid;
schc->curr = ULONG(buf + XEN_HYPER_OFFSET(schedule_data_curr));
if (MEMBER_EXISTS("schedule_data", "idle"))
schc->idle = ULONG(buf + XEN_HYPER_OFFSET(schedule_data_idle));
else
schc->idle = xht->idle_vcpu_array[cpuid];
schc->sched_priv =
ULONG(buf + XEN_HYPER_OFFSET(schedule_data_sched_priv));
if (XEN_HYPER_VALID_MEMBER(schedule_data_tick))
schc->tick = ULONG(buf + XEN_HYPER_OFFSET(schedule_data_tick));
}
FREEBUF(buf);
}
/*
* This should be called after all initailize process finished.
*/
void
xen_hyper_post_init(void)
{
struct xen_hyper_pcpu_context *pcc;
int i, cpuid;
/* set current vcpu to pcpu context */
for_cpu_indexes(i, cpuid)
{
pcc = &xhpct->context_array[cpuid];
if (!pcc->current_vcpu) {
pcc->current_vcpu =
xen_hyper_get_active_vcpu_from_pcpuid(cpuid);
}
}
/* set pcpu last */
if (!(xhpct->last =
xen_hyper_id_to_pcpu_context(XEN_HYPER_CRASHING_CPU()))) {
xhpct->last = &xhpct->context_array[xht->cpu_idxs[0]];
}
/* set vcpu last */
if (xhpct->last) {
xhvct->last =
xen_hyper_vcpu_to_vcpu_context(xhpct->last->current_vcpu);
/* set crashing vcpu */
xht->crashing_vcc = xhvct->last;
}
if (!xhvct->last) {
xhvct->last = xhvct->vcpu_context_arrays->context_array;
}
/* set domain last */
if (xhvct->last) {
xhdt->last =
xen_hyper_domain_to_domain_context(xhvct->last->domain);
}
if (!xhdt->last) {
xhdt->last = xhdt->context_array;
}
}
/*
* Do initialization for dump information here.
*/
void
xen_hyper_dumpinfo_init(void)
{
Elf32_Nhdr *note;
char *buf, *bp, *np, *upp;
char *nccp, *xccp;
ulong addr;
long size;
int i, cpuid, samp_cpuid;
/*
* NOTE kakuma: It is not clear that what kind of
* a elf note format each one of the xen uses.
* So, we decide it confirming whether a symbol exists.
*/
if (STRUCT_EXISTS("note_buf_t"))
xhdit->note_ver = XEN_HYPER_ELF_NOTE_V1;
else if (STRUCT_EXISTS("crash_note_xen_t"))
xhdit->note_ver = XEN_HYPER_ELF_NOTE_V2;
else if (STRUCT_EXISTS("crash_xen_core_t")) {
if (STRUCT_EXISTS("crash_note_xen_core_t"))
xhdit->note_ver = XEN_HYPER_ELF_NOTE_V3;
else
xhdit->note_ver = XEN_HYPER_ELF_NOTE_V4;
} else {
error(WARNING, "found unsupported elf note format while checking of xen dumpinfo.\n");
return;
}
if (!xen_hyper_test_pcpu_id(XEN_HYPER_CRASHING_CPU())) {
error(WARNING, "crashing_cpu not found.\n");
return;
}
/* allocate a context area */
size = sizeof(struct xen_hyper_dumpinfo_context) * machdep->get_smp_cpus();
if((xhdit->context_array = malloc(size)) == NULL) {
error(FATAL, "cannot malloc dumpinfo table context space.\n");
}
BZERO(xhdit->context_array, size);
size = sizeof(struct xen_hyper_dumpinfo_context_xen_core) * machdep->get_smp_cpus();
if((xhdit->context_xen_core_array = malloc(size)) == NULL) {
error(FATAL, "cannot malloc dumpinfo table context_xen_core_array space.\n");
}
BZERO(xhdit->context_xen_core_array, size);
if (symbol_exists("per_cpu__crash_notes"))
addr = symbol_value("per_cpu__crash_notes");
else
get_symbol_data("crash_notes", sizeof(ulong), &addr);
for (i = 0; i < machdep->get_smp_cpus(); i++) {
ulong addr_notes;
if (symbol_exists("per_cpu__crash_notes"))
addr_notes = xen_hyper_per_cpu(addr, i);
else
addr_notes = addr + i * STRUCT_SIZE("crash_note_range_t") +
MEMBER_OFFSET("crash_note_range_t", "start");
if (xhdit->note_ver == XEN_HYPER_ELF_NOTE_V4) {
if (!readmem(addr_notes, KVADDR, &(xhdit->context_array[i].note),
sizeof(ulong), "crash_notes", RETURN_ON_ERROR)) {
error(WARNING, "cannot read crash_notes.\n");
return;
}
} else {
xhdit->context_array[i].note = addr_notes;
}
}
if (xhdit->note_ver == XEN_HYPER_ELF_NOTE_V1) {
xhdit->note_size = XEN_HYPER_SIZE(note_buf_t);
} else if (xhdit->note_ver == XEN_HYPER_ELF_NOTE_V4) {
xhdit->note_size = XEN_HYPER_ELF_NOTE_V4_NOTE_SIZE;
} else {
xhdit->note_size = XEN_HYPER_SIZE(crash_note_t);
}
/* read a sample note */
buf = GETBUF(xhdit->note_size);
if (xhdit->note_ver == XEN_HYPER_ELF_NOTE_V4)
samp_cpuid = xht->cpu_idxs[0];
else
samp_cpuid = XEN_HYPER_CRASHING_CPU();
xhdit->xen_info_cpu = samp_cpuid;
if (!xen_hyper_fill_elf_notes(xhdit->context_array[samp_cpuid].note,
buf, XEN_HYPER_ELF_NOTE_FILL_T_NOTE)) {
error(FATAL, "cannot read crash_notes.\n");
}
bp = buf;
/* Get elf format information for each version. */
switch (xhdit->note_ver) {
case XEN_HYPER_ELF_NOTE_V1:
/* core data */
note = (Elf32_Nhdr *)bp;
np = bp + sizeof(Elf32_Nhdr);
upp = np + note->n_namesz;
upp = (char *)roundup((ulong)upp, 4);
xhdit->core_offset = (Elf_Word)((ulong)upp - (ulong)note);
note = (Elf32_Nhdr *)(upp + note->n_descsz);
/* cr3 data */
np = (char *)note + sizeof(Elf32_Nhdr);
upp = np + note->n_namesz;
upp = (char *)roundup((ulong)upp, 4);
upp = upp + note->n_descsz;
xhdit->core_size = upp - bp;
break;
case XEN_HYPER_ELF_NOTE_V2:
/* core data */
xhdit->core_offset = XEN_HYPER_OFFSET(crash_note_core_t_desc);
xhdit->core_size = XEN_HYPER_SIZE(crash_note_core_t);
/* xen core */
xhdit->xen_info_offset = XEN_HYPER_OFFSET(crash_note_xen_t_desc);
xhdit->xen_info_size = XEN_HYPER_SIZE(crash_note_xen_t);
break;
case XEN_HYPER_ELF_NOTE_V3:
/* core data */
xhdit->core_offset = XEN_HYPER_OFFSET(crash_note_core_t_desc);
xhdit->core_size = XEN_HYPER_SIZE(crash_note_core_t);
/* xen core */
xhdit->xen_core_offset = XEN_HYPER_OFFSET(crash_note_xen_core_t_desc);
xhdit->xen_core_size = XEN_HYPER_SIZE(crash_note_xen_core_t);
/* xen info */
xhdit->xen_info_offset = XEN_HYPER_OFFSET(crash_note_xen_info_t_desc);
xhdit->xen_info_size = XEN_HYPER_SIZE(crash_note_xen_info_t);
break;
case XEN_HYPER_ELF_NOTE_V4:
/* core data */
note = (Elf32_Nhdr *)bp;
np = bp + sizeof(Elf32_Nhdr);
upp = np + note->n_namesz;
upp = (char *)roundup((ulong)upp, 4);
xhdit->core_offset = (Elf_Word)((ulong)upp - (ulong)note);
upp = upp + note->n_descsz;
xhdit->core_size = (Elf_Word)((ulong)upp - (ulong)note);
if (XEN_HYPER_ELF_NOTE_V4_NOTE_SIZE < xhdit->core_size + 32) {
error(WARNING, "note size is assumed on crash is incorrect.(core data)\n");
return;
}
/* xen core */
note = (Elf32_Nhdr *)upp;
np = (char *)note + sizeof(Elf32_Nhdr);
upp = np + note->n_namesz;
upp = (char *)roundup((ulong)upp, 4);
xhdit->xen_core_offset = (Elf_Word)((ulong)upp - (ulong)note);
upp = upp + note->n_descsz;
xhdit->xen_core_size = (Elf_Word)((ulong)upp - (ulong)note);
if (XEN_HYPER_ELF_NOTE_V4_NOTE_SIZE <
xhdit->core_size + xhdit->xen_core_size + 32) {
error(WARNING, "note size is assumed on crash is incorrect.(xen core)\n");
return;
}
/* xen info */
note = (Elf32_Nhdr *)upp;
np = (char *)note + sizeof(Elf32_Nhdr);
upp = np + note->n_namesz;
upp = (char *)roundup((ulong)upp, 4);
xhdit->xen_info_offset = (Elf_Word)((ulong)upp - (ulong)note);
upp = upp + note->n_descsz;
xhdit->xen_info_size = (Elf_Word)((ulong)upp - (ulong)note);
if (XEN_HYPER_ELF_NOTE_V4_NOTE_SIZE <
xhdit->core_size + xhdit->xen_core_size + xhdit->xen_info_size) {
error(WARNING, "note size is assumed on crash is incorrect.(xen info)\n");
return;
}
xhdit->note_size = xhdit->core_size + xhdit->xen_core_size + xhdit->xen_info_size;
break;
default:
error(FATAL, "logic error in cheking elf note format occurs.\n");
}
/* fill xen info context. */
if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V3) {
if((xhdit->crash_note_xen_info_ptr =
malloc(xhdit->xen_info_size)) == NULL) {
error(FATAL, "cannot malloc dumpinfo table "
"crash_note_xen_info_ptr space.\n");
}
memcpy(xhdit->crash_note_xen_info_ptr,
bp + xhdit->core_size + xhdit->xen_core_size,
xhdit->xen_info_size);
xhdit->context_xen_info.note =
xhdit->context_array[samp_cpuid].note +
xhdit->core_size + xhdit->xen_core_size;
xhdit->context_xen_info.pcpu_id = samp_cpuid;
xhdit->context_xen_info.crash_xen_info_ptr =
xhdit->crash_note_xen_info_ptr + xhdit->xen_info_offset;
}
/* allocate note core */
size = xhdit->core_size * XEN_HYPER_NR_PCPUS();
if(!(xhdit->crash_note_core_array = malloc(size))) {
error(FATAL, "cannot malloc crash_note_core_array space.\n");
}
nccp = xhdit->crash_note_core_array;
BZERO(nccp, size);
xccp = NULL;
/* allocate xen core */
if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V2) {
size = xhdit->xen_core_size * XEN_HYPER_NR_PCPUS();
if(!(xhdit->crash_note_xen_core_array = malloc(size))) {
error(FATAL, "cannot malloc dumpinfo table "
"crash_note_xen_core_array space.\n");
}
xccp = xhdit->crash_note_xen_core_array;
BZERO(xccp, size);
}
/* fill a context. */
for_cpu_indexes(i, cpuid)
{
/* fill core context. */
addr = xhdit->context_array[cpuid].note;
if (!xen_hyper_fill_elf_notes(addr, nccp,
XEN_HYPER_ELF_NOTE_FILL_T_CORE)) {
error(FATAL, "cannot read elf note core.\n");
}
xhdit->context_array[cpuid].pcpu_id = cpuid;
xhdit->context_array[cpuid].ELF_Prstatus_ptr =
nccp + xhdit->core_offset;
xhdit->context_array[cpuid].pr_reg_ptr =
nccp + xhdit->core_offset +
XEN_HYPER_OFFSET(ELF_Prstatus_pr_reg);
/* Is there xen core data? */
if (xhdit->note_ver < XEN_HYPER_ELF_NOTE_V2) {
nccp += xhdit->core_size;
continue;
}
if (xhdit->note_ver == XEN_HYPER_ELF_NOTE_V2 &&
cpuid != samp_cpuid) {
xccp += xhdit->xen_core_size;
nccp += xhdit->core_size;
continue;
}
/* fill xen core context, in case of more elf note V2. */
xhdit->context_xen_core_array[cpuid].note =
xhdit->context_array[cpuid].note +
xhdit->core_size;
xhdit->context_xen_core_array[cpuid].pcpu_id = cpuid;
xhdit->context_xen_core_array[cpuid].crash_xen_core_ptr =
xccp + xhdit->xen_core_offset;
if (!xen_hyper_fill_elf_notes(xhdit->context_xen_core_array[cpuid].note,
xccp, XEN_HYPER_ELF_NOTE_FILL_T_XEN_CORE)) {
error(FATAL, "cannot read elf note xen core.\n");
}
xccp += xhdit->xen_core_size;
nccp += xhdit->core_size;
}
FREEBUF(buf);
}
/*
* Get dump information context from physical cpu id.
*/
struct xen_hyper_dumpinfo_context *
xen_hyper_id_to_dumpinfo_context(uint id)
{
if (!xen_hyper_test_pcpu_id(id))
return NULL;
return &xhdit->context_array[id];
}
/*
* Get dump information context from ELF Note address.
*/
struct xen_hyper_dumpinfo_context *
xen_hyper_note_to_dumpinfo_context(ulong note)
{
int i;
for (i = 0; i < XEN_HYPER_MAX_CPUS(); i++) {
if (note == xhdit->context_array[i].note) {
return &xhdit->context_array[i];
}
}
return NULL;
}
/*
* Fill ELF Notes header here.
* This assume that variable note has a top address of an area for
* specified type.
*/
char *
xen_hyper_fill_elf_notes(ulong note, char *note_buf, int type)
{
long size;
ulong rp = note;
if (type == XEN_HYPER_ELF_NOTE_FILL_T_NOTE)
size = xhdit->note_size;
else if (type == XEN_HYPER_ELF_NOTE_FILL_T_CORE)
size = xhdit->core_size;
else if (type == XEN_HYPER_ELF_NOTE_FILL_T_XEN_CORE)
size = xhdit->xen_core_size;
else if (type == XEN_HYPER_ELF_NOTE_FILL_T_XEN_CORE_M)
size = xhdit->core_size + xhdit->xen_core_size;
else if (type == XEN_HYPER_ELF_NOTE_FILL_T_PRS)
size = XEN_HYPER_SIZE(ELF_Prstatus);
else if (type == XEN_HYPER_ELF_NOTE_FILL_T_XEN_REGS)
size = XEN_HYPER_SIZE(xen_crash_xen_regs_t);
else
return NULL;
if (!readmem(rp, KVADDR, note_buf, size,
"note_buf_t or crash_note_t", RETURN_ON_ERROR)) {
if (type == XEN_HYPER_ELF_NOTE_FILL_T_NOTE)
error(WARNING, "cannot fill note_buf_t or crash_note_t.\n");
else if (type == XEN_HYPER_ELF_NOTE_FILL_T_CORE)
error(WARNING, "cannot fill note core.\n");
else if (type == XEN_HYPER_ELF_NOTE_FILL_T_XEN_CORE)
error(WARNING, "cannot fill note xen core.\n");
else if (type == XEN_HYPER_ELF_NOTE_FILL_T_XEN_CORE_M)
error(WARNING, "cannot fill note core & xen core.\n");
else if (type == XEN_HYPER_ELF_NOTE_FILL_T_PRS)
error(WARNING, "cannot fill ELF_Prstatus.\n");
else if (type == XEN_HYPER_ELF_NOTE_FILL_T_XEN_REGS)
error(WARNING, "cannot fill xen_crash_xen_regs_t.\n");
return NULL;
}
return note_buf;
}
/*
* Get domain status.
*/
ulong
xen_hyper_domain_state(struct xen_hyper_domain_context *dc)
{
if (ACTIVE()) {
if (xen_hyper_read_domain_verify(dc->domain) == NULL) {
return XEN_HYPER_DOMF_ERROR;
}
}
return dc->domain_flags;
}
/*
* Allocate domain context space.
*/
void
xen_hyper_refresh_domain_context_space(void)
{
char *domain_struct;
ulong domain, next, dom_xen, dom_io, idle_vcpu;
struct xen_hyper_domain_context *dc;
struct xen_hyper_domain_context *dom0;
int i;
if ((xhdt->flags & XEN_HYPER_DOMAIN_F_INIT) && !ACTIVE()) {
return;
}
XEN_HYPER_RUNNING_DOMAINS() = XEN_HYPER_NR_DOMAINS() =
xen_hyper_get_domains();
xen_hyper_alloc_domain_context_space(XEN_HYPER_NR_DOMAINS());
dc = xhdt->context_array;
/* restore an dom_io context. */
get_symbol_data("dom_io", sizeof(dom_io), &dom_io);
if ((domain_struct = xen_hyper_read_domain(dom_io)) == NULL) {
error(FATAL, "cannot read dom_io.\n");
}
xen_hyper_store_domain_context(dc, dom_io, domain_struct);
xhdt->dom_io = dc;
dc++;
/* restore an dom_xen context. */
get_symbol_data("dom_xen", sizeof(dom_xen), &dom_xen);
if ((domain_struct = xen_hyper_read_domain(dom_xen)) == NULL) {
error(FATAL, "cannot read dom_xen.\n");
}
xen_hyper_store_domain_context(dc, dom_xen, domain_struct);
xhdt->dom_xen = dc;
dc++;
/* restore an idle domain context. */
for (i = 0; i < xht->idle_vcpu_size; i += XEN_HYPER_MAX_VIRT_CPUS) {
idle_vcpu = xht->idle_vcpu_array[i];
if (idle_vcpu == 0)
break;
if (!readmem(idle_vcpu + MEMBER_OFFSET("vcpu", "domain"),
KVADDR, &domain, sizeof(domain), "domain", RETURN_ON_ERROR)) {
error(FATAL, "cannot read domain member in vcpu.\n");
}
if (CRASHDEBUG(1)) {
fprintf(fp, "idle_vcpu=%lx, domain=%lx\n", idle_vcpu, domain);
}
if ((domain_struct = xen_hyper_read_domain(domain)) == NULL) {
error(FATAL, "cannot read idle domain.\n");
}
xen_hyper_store_domain_context(dc, domain, domain_struct);
if (i == 0)
xhdt->idle_domain = dc;
dc++;
}
/* restore domain contexts from dom0 symbol. */
xen_hyper_get_domain_next(XEN_HYPER_DOMAIN_READ_DOM0, &next);
domain = next;
dom0 = dc;
while((domain_struct =
xen_hyper_get_domain_next(XEN_HYPER_DOMAIN_READ_NEXT, &next)) != NULL) {
xen_hyper_store_domain_context(dc, domain, domain_struct);
domain = next;
dc++;
}
xhdt->dom0 = dom0;
}
/*
* Get number of domain.
*/
int
xen_hyper_get_domains(void)
{
ulong domain, next_in_list;
long domain_next_in_list;
int i, j;
if (!try_get_symbol_data("hardware_domain", sizeof(void *), &domain))
get_symbol_data("dom0", sizeof(void *), &domain);
domain_next_in_list = MEMBER_OFFSET("domain", "next_in_list");
i = 0;
while (domain != 0) {
i++;
next_in_list = domain + domain_next_in_list;
if (!readmem(next_in_list, KVADDR, &domain, sizeof(void *),
"domain.next_in_list", RETURN_ON_ERROR)) {
error(FATAL, "cannot read domain.next_in_list.\n");
}
}
i += 2; /* for dom_io, dom_xen */
/* for idle domains */
for (j = 0; j < xht->idle_vcpu_size; j += XEN_HYPER_MAX_VIRT_CPUS) {
if (xht->idle_vcpu_array[j])
i++;
}
return i;
}
/*
* Get next domain struct.
* mod - XEN_HYPER_DOMAIN_READ_DOM0:start from dom0 symbol
* - XEN_HYPER_DOMAIN_READ_INIT:start from xhdt->context_array
* - XEN_HYPER_DOMAIN_READ_NEXT:next
*/
char *
xen_hyper_get_domain_next(int mod, ulong *next)
{
static int idx = 0;
char *domain_struct;
struct xen_hyper_domain_context *dc;
switch (mod) {
case XEN_HYPER_DOMAIN_READ_DOM0:
/* Case of search from dom0 symbol. */
idx = 0;
if (xhdt->dom0) {
*next = xhdt->dom0->domain;
} else {
if (!try_get_symbol_data("hardware_domain", sizeof(void *), next))
get_symbol_data("dom0", sizeof(void *), next);
}
return xhdt->domain_struct;
break;
case XEN_HYPER_DOMAIN_READ_INIT:
/* Case of search from context_array. */
if (xhdt->context_array && xhdt->context_array->domain) {
idx = 1; /* this has a next index. */
*next = xhdt->context_array->domain;
} else {
idx = 0;
*next = 0;
return NULL;
}
return xhdt->domain_struct;
break;
case XEN_HYPER_DOMAIN_READ_NEXT:
break;
default :
error(FATAL, "xen_hyper_get_domain_next mod error: %d\n", mod);
return NULL;
}
/* Finished search */
if (!*next) {
return NULL;
}
domain_struct = NULL;
/* Is domain context array valid? */
if (idx) {
if ((domain_struct =
xen_hyper_read_domain(*next)) == NULL) {
error(FATAL, "cannot get next domain from domain context array.\n");
}
if (idx > XEN_HYPER_NR_DOMAINS()) {
*next = 0;
} else {
dc = xhdt->context_array;
dc += idx;
*next = dc->domain;
idx++;
}
return domain_struct;
}
/* Search from dom0 symbol. */
if ((domain_struct =
xen_hyper_read_domain(*next)) == NULL) {
error(FATAL, "cannot get next domain from dom0 symbol.\n");
}
*next = ULONG(domain_struct + XEN_HYPER_OFFSET(domain_next_in_list));
return domain_struct;
}
/*
* from domain address to id.
*/
domid_t
xen_hyper_domain_to_id(ulong domain)
{
struct xen_hyper_domain_context *dc;
/* Is domain context array valid? */
if (xhdt->context_array && xhdt->context_array->domain) {
if ((dc = xen_hyper_domain_to_domain_context(domain)) == NULL) {
return XEN_HYPER_DOMAIN_ID_INVALID;
} else {
return dc->domain_id;
}
} else {
return XEN_HYPER_DOMAIN_ID_INVALID;
}
}
/*
* Get domain struct from id.
*/
char *
xen_hyper_id_to_domain_struct(domid_t id)
{
char *domain_struct;
struct xen_hyper_domain_context *dc;
domain_struct = NULL;
/* Is domain context array valid? */
if (xhdt->context_array && xhdt->context_array->domain) {
if ((dc = xen_hyper_id_to_domain_context(id)) == NULL) {
return NULL;
} else {
if ((domain_struct =
xen_hyper_read_domain(dc->domain)) == NULL) {
error(FATAL, "cannot get domain from domain context array with id.\n");
}
return domain_struct;
}
} else {
return NULL;
}
}
/*
* Get domain context from domain address.
*/
struct xen_hyper_domain_context *
xen_hyper_domain_to_domain_context(ulong domain)
{
struct xen_hyper_domain_context *dc;
int i;
if (xhdt->context_array == NULL ||
xhdt->context_array->domain == 0) {
return NULL;
}
if (!domain) {
return NULL;
}
for (i = 0, dc = xhdt->context_array; i < XEN_HYPER_NR_DOMAINS();
i++, dc++) {
if (domain == dc->domain) {
return dc;
}
}
return NULL;
}
/*
* Get domain context from domain id.
*/
struct xen_hyper_domain_context *
xen_hyper_id_to_domain_context(domid_t id)
{
struct xen_hyper_domain_context *dc;
int i;
if (xhdt->context_array == NULL ||
xhdt->context_array->domain == 0) {
return NULL;
}
if (id == XEN_HYPER_DOMAIN_ID_INVALID) {
return NULL;
}
for (i = 0, dc = xhdt->context_array; i < XEN_HYPER_NR_DOMAINS();
i++, dc++) {
if (id == dc->domain_id) {
return dc;
}
}
return NULL;
}
/*
* Store domain struct contents.
*/
struct xen_hyper_domain_context *
xen_hyper_store_domain_context(struct xen_hyper_domain_context *dc,
ulong domain, char *dp)
{
char *vcpup;
unsigned int max_vcpus;
unsigned int i;
dc->domain = domain;
BCOPY((char *)(dp + XEN_HYPER_OFFSET(domain_domain_id)),
&dc->domain_id, sizeof(domid_t));
dc->tot_pages = UINT(dp + XEN_HYPER_OFFSET(domain_tot_pages));
dc->max_pages = UINT(dp + XEN_HYPER_OFFSET(domain_max_pages));
dc->xenheap_pages = UINT(dp + XEN_HYPER_OFFSET(domain_xenheap_pages));
dc->shared_info = ULONG(dp + XEN_HYPER_OFFSET(domain_shared_info));
dc->sched_priv = ULONG(dp + XEN_HYPER_OFFSET(domain_sched_priv));
dc->next_in_list = ULONG(dp + XEN_HYPER_OFFSET(domain_next_in_list));
if (XEN_HYPER_VALID_MEMBER(domain_domain_flags))
dc->domain_flags = ULONG(dp + XEN_HYPER_OFFSET(domain_domain_flags));
else if (XEN_HYPER_VALID_MEMBER(domain_is_shut_down)) {
dc->domain_flags = 0;
if (XEN_HYPER_VALID_MEMBER(domain_is_hvm) &&
*(dp + XEN_HYPER_OFFSET(domain_is_hvm))) {
dc->domain_flags |= XEN_HYPER_DOMS_HVM;
}
if (XEN_HYPER_VALID_MEMBER(domain_guest_type) &&
*(dp + XEN_HYPER_OFFSET(domain_guest_type))) {
/* For now PVH and HVM are the same for crash.
* and 0 is PV.
*/
dc->domain_flags |= XEN_HYPER_DOMS_HVM;
}
if (*(dp + XEN_HYPER_OFFSET(domain_is_privileged))) {
dc->domain_flags |= XEN_HYPER_DOMS_privileged;
}
if (*(dp + XEN_HYPER_OFFSET(domain_debugger_attached))) {
dc->domain_flags |= XEN_HYPER_DOMS_debugging;
}
if (XEN_HYPER_VALID_MEMBER(domain_is_polling) &&
*(dp + XEN_HYPER_OFFSET(domain_is_polling))) {
dc->domain_flags |= XEN_HYPER_DOMS_polling;
}
if (XEN_HYPER_VALID_MEMBER(domain_is_paused_by_controller) &&
*(dp + XEN_HYPER_OFFSET(domain_is_paused_by_controller))) {
dc->domain_flags |= XEN_HYPER_DOMS_ctrl_pause;
}
if (XEN_HYPER_VALID_MEMBER(domain_controller_pause_count) &&
*(dp + XEN_HYPER_OFFSET(domain_controller_pause_count))) {
dc->domain_flags |= XEN_HYPER_DOMS_ctrl_pause;
}
if (*(dp + XEN_HYPER_OFFSET(domain_is_dying))) {
dc->domain_flags |= XEN_HYPER_DOMS_dying;
}
if (*(dp + XEN_HYPER_OFFSET(domain_is_shutting_down))) {
dc->domain_flags |= XEN_HYPER_DOMS_shuttingdown;
}
if (*(dp + XEN_HYPER_OFFSET(domain_is_shut_down))) {
dc->domain_flags |= XEN_HYPER_DOMS_shutdown;
}
} else {
dc->domain_flags = XEN_HYPER_DOMF_ERROR;
}
dc->evtchn = ULONG(dp + XEN_HYPER_OFFSET(domain_evtchn));
if (XEN_HYPER_VALID_MEMBER(domain_max_vcpus)) {
max_vcpus = UINT(dp + XEN_HYPER_OFFSET(domain_max_vcpus));
} else if (XEN_HYPER_VALID_SIZE(domain_vcpu)) {
max_vcpus = XEN_HYPER_SIZE(domain_vcpu) / sizeof(void *);
} else {
max_vcpus = XEN_HYPER_MAX_VIRT_CPUS;
}
if (!(dc->vcpu = malloc(sizeof(ulong) * max_vcpus))) {
error(FATAL, "cannot malloc vcpu array (%d VCPUs).",
max_vcpus);
}
if (MEMBER_TYPE("domain", "vcpu") == TYPE_CODE_ARRAY)
vcpup = dp + XEN_HYPER_OFFSET(domain_vcpu);
else {
ulong vcpu_array = ULONG(dp + XEN_HYPER_OFFSET(domain_vcpu));
if (vcpu_array && max_vcpus) {
if (!(vcpup =
malloc(max_vcpus * sizeof(void *)))) {
error(FATAL, "cannot malloc VCPU array for domain %lx.",
domain);
}
if (!readmem(vcpu_array, KVADDR,
vcpup, max_vcpus * sizeof(void*),
"VCPU array", RETURN_ON_ERROR)) {
error(FATAL, "cannot read VCPU array for domain %lx.",
domain);
}
} else {
vcpup = NULL;
}
}
if (vcpup) {
for (i = 0; i < max_vcpus; i++) {
dc->vcpu[i] = ULONG(vcpup + i*sizeof(void *));
if (dc->vcpu[i]) XEN_HYPER_NR_VCPUS_IN_DOM(dc)++;
}
if (vcpup != dp + XEN_HYPER_OFFSET(domain_vcpu)) {
free(vcpup);
}
}
return dc;
}
/*
* Read domain struct from domain context.
*/
char *
xen_hyper_read_domain_from_context(struct xen_hyper_domain_context *dc)
{
return xen_hyper_fill_domain_struct(dc->domain, xhdt->domain_struct);
}
/*
* Read domain struct.
*/
char *
xen_hyper_read_domain(ulong domain)
{
return xen_hyper_fill_domain_struct(domain, xhdt->domain_struct);
}
/*
* Read domain struct to verification.
*/
char *
xen_hyper_read_domain_verify(ulong domain)
{
return xen_hyper_fill_domain_struct(domain, xhdt->domain_struct_verify);
}
/*
* Fill domain struct.
*/
char *
xen_hyper_fill_domain_struct(ulong domain, char *domain_struct)
{
if (!readmem(domain, KVADDR, domain_struct,
XEN_HYPER_SIZE(domain), "fill_domain_struct",
ACTIVE() ? (RETURN_ON_ERROR|QUIET) : RETURN_ON_ERROR)) {
error(WARNING, "cannot fill domain struct.\n");
return NULL;
}
return domain_struct;
}
/*
* Allocate domain context space.
*/
void
xen_hyper_alloc_domain_context_space(int domains)
{
if (xhdt->context_array == NULL) {
if (!(xhdt->context_array =
malloc(domains * sizeof(struct xen_hyper_domain_context)))) {
error(FATAL, "cannot malloc context array (%d domains).",
domains);
}
xhdt->context_array_cnt = domains;
} else if (domains > xhdt->context_array_cnt) {
struct xen_hyper_domain_context *dc;
int i;
for (dc = xhdt->context_array, i = 0;
i < xhdt->context_array_cnt; ++dc, ++i) {
if (dc->vcpu)
free(dc->vcpu);
}
if (!(xhdt->context_array =
realloc(xhdt->context_array,
domains * sizeof(struct xen_hyper_domain_context)))) {
error(FATAL, "cannot realloc context array (%d domains).",
domains);
}
xhdt->context_array_cnt = domains;
}
BZERO(xhdt->context_array,
domains * sizeof(struct xen_hyper_domain_context));
}
/*
* Get vcpu status.
*/
int
xen_hyper_vcpu_state(struct xen_hyper_vcpu_context *vcc)
{
if (ACTIVE()) {
if (xen_hyper_read_vcpu_verify(vcc->vcpu) == NULL) {
return XEN_HYPER_RUNSTATE_ERROR;
}
}
return vcc->state;
}
/*
* Allocate vcpu context space.
*/
void
xen_hyper_refresh_vcpu_context_space(void)
{
struct xen_hyper_domain_context *dc;
struct xen_hyper_vcpu_context_array *vcca;
struct xen_hyper_vcpu_context *vcc;
int i, j;
if ((xhvct->flags & XEN_HYPER_VCPU_F_INIT) && !ACTIVE()) {
return;
}
xen_hyper_alloc_vcpu_context_arrays_space(XEN_HYPER_NR_DOMAINS());
for (i = 0, xht->vcpus = 0, dc = xhdt->context_array,
vcca = xhvct->vcpu_context_arrays;
i < XEN_HYPER_NR_DOMAINS(); i++, dc++, vcca++) {
dc->vcpu_context_array = vcca;
xen_hyper_alloc_vcpu_context_space(vcca,
XEN_HYPER_NR_VCPUS_IN_DOM(dc));
for (j = 0, vcc = vcca->context_array;
j < XEN_HYPER_NR_VCPUS_IN_DOM(dc); j++, vcc++) {
xen_hyper_read_vcpu(dc->vcpu[j]);
xen_hyper_store_vcpu_context(vcc, dc->vcpu[j],
xhvct->vcpu_struct);
}
if (dc == xhdt->idle_domain) {
xhvct->idle_vcpu_context_array = vcca;
}
xht->vcpus += vcca->context_array_cnt;
}
}
/*
* Get vcpu context from vcpu address.
*/
struct xen_hyper_vcpu_context *
xen_hyper_vcpu_to_vcpu_context(ulong vcpu)
{
struct xen_hyper_vcpu_context_array *vcca;
struct xen_hyper_vcpu_context *vcc;
int i, j;
if (!vcpu) {
return NULL;
}
for (i = 0, vcca = xhvct->vcpu_context_arrays;
i < xhvct->vcpu_context_arrays_cnt; i++, vcca++) {
for (j = 0, vcc = vcca->context_array;
j < vcca->context_array_cnt; j++, vcc++) {
if (vcpu == vcc->vcpu) {
return vcc;
}
}
}
return NULL;
}
/*
* Get vcpu context.
*/
struct xen_hyper_vcpu_context *
xen_hyper_id_to_vcpu_context(ulong domain, domid_t did, int vcid)
{
struct xen_hyper_vcpu_context_array *vcca;
struct xen_hyper_vcpu_context *vcc;
int i;
if (vcid == XEN_HYPER_VCPU_ID_INVALID) {
return NULL;
}
if ((vcca = xen_hyper_domain_to_vcpu_context_array(domain))) {
;
} else if (!(vcca = xen_hyper_domid_to_vcpu_context_array(did))) {
return NULL;
}
for (i = 0, vcc = vcca->context_array;
i < vcca->context_array_cnt; i++, vcc++) {
if (vcid == vcc->vcpu_id) {
return vcc;
}
}
return NULL;
}
/*
* Get pointer of a vcpu context array from domain address.
*/
struct xen_hyper_vcpu_context_array *
xen_hyper_domain_to_vcpu_context_array(ulong domain)
{
struct xen_hyper_domain_context *dc;
if(!(dc = xen_hyper_domain_to_domain_context(domain))) {
return NULL;
}
return dc->vcpu_context_array;
}
/*
* Get pointer of a vcpu context array from domain id.
*/
struct xen_hyper_vcpu_context_array *
xen_hyper_domid_to_vcpu_context_array(domid_t id)
{
struct xen_hyper_domain_context *dc;
if (!(dc = xen_hyper_id_to_domain_context(id))) {
return NULL;
}
return dc->vcpu_context_array;
}
/*
* Store vcpu struct contents.
*/
struct xen_hyper_vcpu_context *
xen_hyper_store_vcpu_context(struct xen_hyper_vcpu_context *vcc,
ulong vcpu, char *vcp)
{
vcc->vcpu = vcpu;
vcc->vcpu_id = INT(vcp + XEN_HYPER_OFFSET(vcpu_vcpu_id));
vcc->processor = INT(vcp + XEN_HYPER_OFFSET(vcpu_processor));
vcc->vcpu_info = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_vcpu_info));
vcc->domain = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_domain));
vcc->next_in_list = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_next_in_list));
if (XEN_HYPER_VALID_MEMBER(vcpu_sleep_tick))
vcc->sleep_tick = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_sleep_tick));
if (XEN_HYPER_VALID_MEMBER(vcpu_sched_priv))
vcc->sched_priv = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_sched_priv));
vcc->state = INT(vcp + XEN_HYPER_OFFSET(vcpu_runstate) +
XEN_HYPER_OFFSET(vcpu_runstate_info_state));
vcc->state_entry_time = ULONGLONG(vcp +
XEN_HYPER_OFFSET(vcpu_runstate) +
XEN_HYPER_OFFSET(vcpu_runstate_info_state_entry_time));
vcc->runstate_guest = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_runstate_guest));
if (XEN_HYPER_VALID_MEMBER(vcpu_vcpu_flags))
vcc->vcpu_flags = ULONG(vcp + XEN_HYPER_OFFSET(vcpu_vcpu_flags));
else
vcc->vcpu_flags = XEN_HYPER_VCPUF_ERROR;
return vcc;
}
/*
* Read vcpu struct from vcpu context.
*/
char *
xen_hyper_read_vcpu_from_context(struct xen_hyper_vcpu_context *vcc)
{
return xen_hyper_fill_vcpu_struct(vcc->vcpu, xhvct->vcpu_struct);
}
/*
* Read vcpu struct.
*/
char *
xen_hyper_read_vcpu(ulong vcpu)
{
return xen_hyper_fill_vcpu_struct(vcpu, xhvct->vcpu_struct);
}
/*
* Read vcpu struct to verification.
*/
char *
xen_hyper_read_vcpu_verify(ulong vcpu)
{
return xen_hyper_fill_vcpu_struct(vcpu, xhvct->vcpu_struct_verify);
}
/*
* Fill vcpu struct.
*/
char *
xen_hyper_fill_vcpu_struct(ulong vcpu, char *vcpu_struct)
{
if (!readmem(vcpu, KVADDR, vcpu_struct,
XEN_HYPER_SIZE(vcpu), "fill_vcpu_struct",
ACTIVE() ? (RETURN_ON_ERROR|QUIET) : RETURN_ON_ERROR)) {
error(WARNING, "cannot fill vcpu struct.\n");
return NULL;
}
return vcpu_struct;
}
/*
* Allocate vcpu context arrays space.
*/
void
xen_hyper_alloc_vcpu_context_arrays_space(int domains)
{
struct xen_hyper_vcpu_context_array *vcca;
if (xhvct->vcpu_context_arrays == NULL) {
if (!(xhvct->vcpu_context_arrays =
malloc(domains * sizeof(struct xen_hyper_vcpu_context_array)))) {
error(FATAL, "cannot malloc context arrays (%d domains).",
domains);
}
BZERO(xhvct->vcpu_context_arrays, domains * sizeof(struct xen_hyper_vcpu_context_array));
xhvct->vcpu_context_arrays_cnt = domains;
} else if (domains > xhvct->vcpu_context_arrays_cnt) {
if (!(xhvct->vcpu_context_arrays =
realloc(xhvct->vcpu_context_arrays,
domains * sizeof(struct xen_hyper_vcpu_context_array)))) {
error(FATAL, "cannot realloc context arrays (%d domains).",
domains);
}
vcca = xhvct->vcpu_context_arrays + domains;
BZERO(vcca, (domains - xhvct->vcpu_context_arrays_cnt) *
sizeof(struct xen_hyper_vcpu_context_array));
xhvct->vcpu_context_arrays_cnt = domains;
}
}
/*
* Allocate vcpu context space.
*/
void
xen_hyper_alloc_vcpu_context_space(struct xen_hyper_vcpu_context_array *vcca, int vcpus)
{
if (!vcpus) {
if (vcca->context_array != NULL) {
free(vcca->context_array);
vcca->context_array = NULL;
}
vcca->context_array_cnt = vcpus;
} else if (vcca->context_array == NULL) {
if (!(vcca->context_array =
malloc(vcpus * sizeof(struct xen_hyper_vcpu_context)))) {
error(FATAL, "cannot malloc context array (%d vcpus).",
vcpus);
}
vcca->context_array_cnt = vcpus;
} else if (vcpus > vcca->context_array_cnt) {
if (!(vcca->context_array =
realloc(vcca->context_array,
vcpus * sizeof(struct xen_hyper_vcpu_context_array)))) {
error(FATAL, "cannot realloc context array (%d vcpus).",
vcpus);
}
vcca->context_array_cnt = vcpus;
}
vcca->context_array_valid = vcpus;
BZERO(vcca->context_array, vcpus * sizeof(struct xen_hyper_vcpu_context));
}
/*
* Get pcpu context from pcpu id.
*/
struct xen_hyper_pcpu_context *
xen_hyper_id_to_pcpu_context(uint id)
{
if (xhpct->context_array == NULL) {
return NULL;
}
if (!xen_hyper_test_pcpu_id(id)) {
return NULL;
}
return &xhpct->context_array[id];
}
/*
* Get pcpu context from pcpu address.
*/
struct xen_hyper_pcpu_context *
xen_hyper_pcpu_to_pcpu_context(ulong pcpu)
{
struct xen_hyper_pcpu_context *pcc;
int i;
uint cpuid;
if (xhpct->context_array == NULL) {
return NULL;
}
if (!pcpu) {
return NULL;
}
for_cpu_indexes(i, cpuid)
{
pcc = &xhpct->context_array[cpuid];
if (pcpu == pcc->pcpu) {
return pcc;
}
}
return NULL;
}
/*
* Store pcpu struct contents.
*/
struct xen_hyper_pcpu_context *
xen_hyper_store_pcpu_context(struct xen_hyper_pcpu_context *pcc,
ulong pcpu, char *pcp)
{
pcc->pcpu = pcpu;
pcc->processor_id =
UINT(pcp + XEN_HYPER_OFFSET(cpu_info_processor_id));
pcc->guest_cpu_user_regs = (ulong)(pcpu +
XEN_HYPER_OFFSET(cpu_info_guest_cpu_user_regs));
pcc->current_vcpu =
ULONG(pcp + XEN_HYPER_OFFSET(cpu_info_current_vcpu));
return pcc;
}
/*
* Store init_tss contents.
*/
struct xen_hyper_pcpu_context *
xen_hyper_store_pcpu_context_tss(struct xen_hyper_pcpu_context *pcc,
ulong init_tss, char *tss)
{
int i;
uint64_t *ist_p;
pcc->init_tss = init_tss;
if (machine_type("X86")) {
pcc->sp.esp0 = ULONG(tss + XEN_HYPER_OFFSET(tss_esp0));
} else if (machine_type("X86_64")) {
pcc->sp.rsp0 = ULONG(tss + XEN_HYPER_OFFSET(tss_rsp0));
ist_p = (uint64_t *)(tss + XEN_HYPER_OFFSET(tss_ist));
for (i = 0; i < XEN_HYPER_TSS_IST_MAX; i++, ist_p++) {
pcc->ist[i] = ULONG(ist_p);
}
}
return pcc;
}
/*
* Read pcpu struct.
*/
char *
xen_hyper_read_pcpu(ulong pcpu)
{
return xen_hyper_fill_pcpu_struct(pcpu, xhpct->pcpu_struct);
}
/*
* Fill pcpu struct.
*/
char *
xen_hyper_fill_pcpu_struct(ulong pcpu, char *pcpu_struct)
{
if (!readmem(pcpu, KVADDR, pcpu_struct,
XEN_HYPER_SIZE(cpu_info), "fill_pcpu_struct",
ACTIVE() ? (RETURN_ON_ERROR|QUIET) : RETURN_ON_ERROR)) {
error(WARNING, "cannot fill pcpu_struct.\n");
return NULL;
}
return pcpu_struct;
}
/*
* Allocate pcpu context space.
*/
void
xen_hyper_alloc_pcpu_context_space(int pcpus)
{
if (xhpct->context_array == NULL) {
if (!(xhpct->context_array =
malloc(pcpus * sizeof(struct xen_hyper_pcpu_context)))) {
error(FATAL, "cannot malloc context array (%d pcpus).",
pcpus);
}
}
BZERO(xhpct->context_array, pcpus * sizeof(struct xen_hyper_pcpu_context));
}
/*
* Fill cpu_data.
*/
char *
xen_hyper_x86_fill_cpu_data(int idx, char *cpuinfo_x86)
{
ulong cpu_data;
if (!xen_hyper_test_pcpu_id(idx) || !xht->cpu_data_address)
return NULL;
cpu_data = xht->cpu_data_address + XEN_HYPER_SIZE(cpuinfo_x86) * idx;
if (!readmem(cpu_data, KVADDR, cpuinfo_x86, XEN_HYPER_SIZE(cpuinfo_x86),
"cpu_data", RETURN_ON_ERROR)) {
error(WARNING, "cannot read cpu_data.\n");
return NULL;
}
return cpuinfo_x86;
}
char *
xen_hyper_ia64_fill_cpu_data(int idx, char *cpuinfo_ia64)
{
ulong cpu_data;
if (!xen_hyper_test_pcpu_id(idx) || !xht->cpu_data_address)
return NULL;
cpu_data = xen_hyper_per_cpu(xht->cpu_data_address, idx);
if (!readmem(cpu_data, KVADDR, cpuinfo_ia64, XEN_HYPER_SIZE(cpuinfo_ia64),
"cpu_data", RETURN_ON_ERROR)) {
error(WARNING, "cannot read cpu_data.\n");
return NULL;
}
return cpuinfo_ia64;
}
/*
* Return whether vcpu is crashing.
*/
int
xen_hyper_is_vcpu_crash(struct xen_hyper_vcpu_context *vcc)
{
if (vcc == xht->crashing_vcc)
return TRUE;
return FALSE;
}
/*
* Test whether cpu for pcpu id exists.
*/
int
xen_hyper_test_pcpu_id(uint pcpu_id)
{
ulong *cpumask = xht->cpumask;
uint i, j;
if (pcpu_id == XEN_HYPER_PCPU_ID_INVALID ||
pcpu_id > XEN_HYPER_MAX_CPUS()) {
return FALSE;
}
i = pcpu_id / (sizeof(ulong) * 8);
j = pcpu_id % (sizeof(ulong) * 8);
cpumask += i;
if (*cpumask & (1UL << j)) {
return TRUE;
} else {
return FALSE;
}
}
/*
* Calculate and return the uptime.
*/
ulonglong
xen_hyper_get_uptime_hyper(void)
{
ulong jiffies, tmp1, tmp2;
ulonglong jiffies_64, wrapped;
if (symbol_exists("jiffies_64")) {
get_symbol_data("jiffies_64", sizeof(ulonglong), &jiffies_64);
wrapped = (jiffies_64 & 0xffffffff00000000ULL);
if (wrapped) {
wrapped -= 0x100000000ULL;
jiffies_64 &= 0x00000000ffffffffULL;
jiffies_64 |= wrapped;
jiffies_64 += (ulonglong)(300*machdep->hz);
} else {
tmp1 = (ulong)(uint)(-300*machdep->hz);
tmp2 = (ulong)jiffies_64;
jiffies_64 = (ulonglong)(tmp2 - tmp1);
}
} else if (symbol_exists("jiffies")) {
get_symbol_data("jiffies", sizeof(long), &jiffies);
jiffies_64 = (ulonglong)jiffies;
} else {
jiffies_64 = 0; /* hypervisor does not have uptime */
}
return jiffies_64;
}
/*
* Get cpu informatin around.
*/
void
xen_hyper_get_cpu_info(void)
{
ulong addr, init_begin, init_end;
ulong *cpumask;
uint *cpu_idx;
int i, j, cpus;
XEN_HYPER_STRUCT_SIZE_INIT(cpumask_t, "cpumask_t");
if (symbol_exists("nr_cpu_ids"))
get_symbol_data("nr_cpu_ids", sizeof(uint), &xht->max_cpus);
else {
init_begin = symbol_value("__init_begin");
init_end = symbol_value("__init_end");
addr = symbol_value("max_cpus");
if (addr >= init_begin && addr < init_end)
xht->max_cpus = XEN_HYPER_SIZE(cpumask_t) * 8;
else {
get_symbol_data("max_cpus", sizeof(xht->max_cpus), &xht->max_cpus);
if (XEN_HYPER_SIZE(cpumask_t) * 8 > xht->max_cpus)
xht->max_cpus = XEN_HYPER_SIZE(cpumask_t) * 8;
}
}
if (xht->cpumask) {
free(xht->cpumask);
}
if((xht->cpumask = malloc(XEN_HYPER_SIZE(cpumask_t))) == NULL) {
error(FATAL, "cannot malloc cpumask space.\n");
}
addr = symbol_value("cpu_present_map");
if (!readmem(addr, KVADDR, xht->cpumask,
XEN_HYPER_SIZE(cpumask_t), "cpu_present_map", RETURN_ON_ERROR)) {
error(FATAL, "cannot read cpu_present_map.\n");
}
if (xht->cpu_idxs) {
free(xht->cpu_idxs);
}
if((xht->cpu_idxs = malloc(sizeof(uint) * XEN_HYPER_MAX_CPUS())) == NULL) {
error(FATAL, "cannot malloc cpu_idxs space.\n");
}
memset(xht->cpu_idxs, 0xff, sizeof(uint) * XEN_HYPER_MAX_CPUS());
for (i = cpus = 0, cpumask = xht->cpumask, cpu_idx = xht->cpu_idxs;
i < (XEN_HYPER_SIZE(cpumask_t)/sizeof(ulong)); i++, cpumask++) {
for (j = 0; j < sizeof(ulong) * 8; j++) {
if (*cpumask & (1UL << j)) {
*cpu_idx++ = i * sizeof(ulong) * 8 + j;
cpus++;
}
}
}
xht->pcpus = cpus;
}
/*
* Calculate the number of physical cpu for x86.
*/
int
xen_hyper_x86_get_smp_cpus(void)
{
if (xht->pcpus) {
return xht->pcpus;
}
xen_hyper_get_cpu_info();
return xht->pcpus;
}
/*
* Calculate used memory size for x86.
*/
uint64_t
xen_hyper_x86_memory_size(void)
{
ulong vaddr;
if (machdep->memsize) {
return machdep->memsize;
}
vaddr = symbol_value("total_pages");
if (!readmem(vaddr, KVADDR, &xht->total_pages, sizeof(xht->total_pages),
"total_pages", RETURN_ON_ERROR)) {
error(WARNING, "cannot read total_pages.\n");
}
xht->sys_pages = xht->total_pages;
machdep->memsize = (uint64_t)(xht->sys_pages) * (uint64_t)(machdep->pagesize);
return machdep->memsize;
}
/*
* Calculate the number of physical cpu for ia64.
*/
int
xen_hyper_ia64_get_smp_cpus(void)
{
return xen_hyper_x86_get_smp_cpus();
}
/*
* Calculate used memory size for ia64.
*/
uint64_t
xen_hyper_ia64_memory_size(void)
{
return xen_hyper_x86_memory_size();
}
/*
* Calculate and return the speed of the processor.
*/
ulong
xen_hyper_ia64_processor_speed(void)
{
ulong mhz, proc_freq;
if (machdep->mhz)
return(machdep->mhz);
mhz = 0;
if (!xht->cpu_data_address ||
!XEN_HYPER_VALID_STRUCT(cpuinfo_ia64) ||
XEN_HYPER_INVALID_MEMBER(cpuinfo_ia64_proc_freq))
return (machdep->mhz = mhz);
readmem(xen_hyper_per_cpu(xht->cpu_data_address, xht->cpu_idxs[0]) +
XEN_HYPER_OFFSET(cpuinfo_ia64_proc_freq),
KVADDR, &proc_freq, sizeof(ulong),
"cpuinfo_ia64 proc_freq", FAULT_ON_ERROR);
mhz = proc_freq/1000000;
return (machdep->mhz = mhz);
}
/*
* Print an aligned string with specified length.
*/
void
xen_hyper_fpr_indent(FILE *fp, int len, char *str1, char *str2, int flag)
{
char buf[XEN_HYPER_CMD_BUFSIZE];
int sl, r;
char *s1, *s2;
sl = strlen(str1);
if (sl > len) {
r = 0;
} else {
r = len - sl;
}
memset(buf, ' ', sizeof(buf));
buf[r] = '\0';
if (flag & XEN_HYPER_PRI_L) {
s1 = str1;
s2 = buf;
} else {
s1 = buf;
s2 = str1;
}
if (str2) {
fprintf(fp, "%s%s%s", s1, s2, str2);
} else {
fprintf(fp, "%s%s", s1, s2);
}
if (flag & XEN_HYPER_PRI_LF) {
fprintf(fp, "\n");
}
}
ulong
xen_hyper_get_active_vcpu_from_pcpuid(ulong pcpuid)
{
struct xen_hyper_pcpu_context *pcc;
struct xen_hyper_vcpu_context_array *vcca;
struct xen_hyper_vcpu_context *vcc;
int i, j;
if (!xen_hyper_test_pcpu_id(pcpuid))
return 0;
pcc = &xhpct->context_array[pcpuid];
if (pcc->current_vcpu)
return pcc->current_vcpu;
for (i = 0, vcca = xhvct->vcpu_context_arrays;
i < xhvct->vcpu_context_arrays_cnt; i++, vcca++) {
for (j = 0, vcc = vcca->context_array;
j < vcca->context_array_cnt; j++, vcc++) {
if (vcc->processor == pcpuid &&
vcc->state == XEN_HYPER_RUNSTATE_running) {
return vcc->vcpu;
}
}
}
return 0;
}
ulong
xen_hyper_pcpu_to_active_vcpu(ulong pcpu)
{
ulong vcpu;
/* if pcpu is vcpu address, return it. */
if (pcpu & (~(PAGESIZE() - 1))) {
return pcpu;
}
if(!(vcpu = XEN_HYPER_CURR_VCPU(pcpu)))
error(FATAL, "invalid pcpu id\n");
return vcpu;
}
void
xen_hyper_print_bt_header(FILE *out, ulong vcpu, int newline)
{
struct xen_hyper_vcpu_context *vcc;
if (newline)
fprintf(out, "\n");
vcc = xen_hyper_vcpu_to_vcpu_context(vcpu);
if (!vcc)
error(FATAL, "invalid vcpu\n");
fprintf(out, "PCPU: %2d VCPU: %lx\n", vcc->processor, vcpu);
}
#endif