crash/xen_hyper_command.c
2014-01-28 16:46:11 -05:00

1868 lines
46 KiB
C

/*
* xen_hyper_command.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"
#ifdef X86
char *xhregt[] = {
"ebx", "ecx", "edx", "esi", "edi", "ebp", "eax", "ds", "es",
"fs", "gs", "orig_eax", "eip", "cs", "eflags", "esp", "ss",
NULL
};
#endif
#ifdef X86_64
char *xhregt[] = {
"r15", "r14", "r13", "r12", "rbp", "rbx", "r11", "r10", "r9", "r8",
"rax", "rcx", "rdx", "rsi", "rdi", "orig_rax", "rip", "cs", "eflags",
"rsp", "ss", "fs", "gs", "ds", "es", "fs", "gs",
NULL
};
#endif
#ifdef IA64
char *xhregt[] = {
"aaa", "bbb",
NULL
};
#endif
static void xen_hyper_do_domain(struct xen_hyper_cmd_args *da);
static void xen_hyper_do_doms(struct xen_hyper_cmd_args *da);
static void xen_hyper_show_doms(struct xen_hyper_domain_context *dc);
static void xen_hyper_do_dumpinfo(ulong flag, struct xen_hyper_cmd_args *dia);
static void xen_hyper_show_dumpinfo(ulong flag,
struct xen_hyper_dumpinfo_context *dic);
static void xen_hyper_do_pcpus(ulong flag, struct xen_hyper_cmd_args *pca);
static void xen_hyper_show_pcpus(ulong flag, struct xen_hyper_pcpu_context *pcc);
static void xen_hyper_do_sched(ulong flag, struct xen_hyper_cmd_args *scha);
static void xen_hyper_show_sched(ulong flag, struct xen_hyper_sched_context *schc);
static void xen_hyper_do_vcpu(struct xen_hyper_cmd_args *vca);
static void xen_hyper_do_vcpus(struct xen_hyper_cmd_args *vca);
static void xen_hyper_show_vcpus(struct xen_hyper_vcpu_context *vcc);
static char *xen_hyper_domain_to_type(ulong domain, int *type, char *buf, int verbose);
static char *xen_hyper_domain_context_to_type(
struct xen_hyper_domain_context *dc, int *type, char *buf, int verbose);
static int xen_hyper_str_to_domain_context(char *string, ulong *value,
struct xen_hyper_domain_context **dcp);
static int xen_hyper_str_to_dumpinfo_context(char *string, ulong *value, struct xen_hyper_dumpinfo_context **dicp);
static int xen_hyper_strvcpu_to_vcpu_context(char *string, ulong *value,
struct xen_hyper_vcpu_context **vccp);
static int
xen_hyper_strid_to_vcpu_context(char *strdom, char *strvc, ulong *valdom,
ulong *valvc, struct xen_hyper_vcpu_context **vccp);
static int xen_hyper_str_to_pcpu_context(char *string, ulong *value,
struct xen_hyper_pcpu_context **pccp);
/*
* Display domain struct.
*/
void
xen_hyper_cmd_domain(void)
{
struct xen_hyper_cmd_args da;
struct xen_hyper_domain_context *dc;
ulong val;
int c, cnt, type, bogus;
BZERO(&da, sizeof(struct xen_hyper_cmd_args));
while ((c = getopt(argcnt, args, "")) != EOF) {
switch(c)
{
default:
argerrs++;
break;
}
}
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
cnt = bogus = 0;
while (args[optind]) {
if (IS_A_NUMBER(args[optind])) {
type = xen_hyper_str_to_domain_context(args[optind], &val, &dc);
switch (type) {
case XEN_HYPER_STR_DID:
case XEN_HYPER_STR_DOMAIN:
da.value[cnt] = val;
da.type[cnt] = type;
da.addr[cnt] = dc->domain;
da.context[cnt] = dc;
cnt++;
break;
case XEN_HYPER_STR_INVALID:
error(INFO, "invalid domain or id value: %s\n\n",
args[optind]);
bogus++;
}
} else {
error(FATAL, "invalid address: %s\n",
args[optind]);
}
optind++;
}
da.cnt = cnt;
if (bogus && !cnt) {
return;
}
xen_hyper_do_domain(&da);
}
/*
* Do the work requested by xen_hyper_cmd_dom().
*/
static void
xen_hyper_do_domain(struct xen_hyper_cmd_args *da)
{
int i;
if (da->cnt) {
if (da->cnt == 1) {
xhdt->last = da->context[0];
}
for (i = 0; i < da->cnt; i++) {
dump_struct("domain", da->addr[i], 0);
}
} else {
dump_struct("domain", xhdt->last->domain, 0);
}
}
/*
* Display domain status.
*/
void
xen_hyper_cmd_doms(void)
{
struct xen_hyper_cmd_args da;
struct xen_hyper_domain_context *dc;
ulong val;
int c, cnt, type, bogus;
BZERO(&da, sizeof(struct xen_hyper_cmd_args));
while ((c = getopt(argcnt, args, "")) != EOF) {
switch(c)
{
default:
argerrs++;
break;
}
}
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
cnt = bogus = 0;
while (args[optind]) {
if (IS_A_NUMBER(args[optind])) {
type = xen_hyper_str_to_domain_context(args[optind], &val, &dc);
switch (type) {
case XEN_HYPER_STR_DID:
case XEN_HYPER_STR_DOMAIN:
da.value[cnt] = val;
da.type[cnt] = type;
da.addr[cnt] = dc->domain;
da.context[cnt] = dc;
cnt++;
break;
case XEN_HYPER_STR_INVALID:
error(INFO, "invalid domain or id value: %s\n\n",
args[optind]);
bogus++;
}
} else {
error(FATAL, "invalid address: %s\n",
args[optind]);
}
optind++;
}
da.cnt = cnt;
if (bogus && !cnt) {
return;
}
xen_hyper_do_doms(&da);
}
/*
* Do the work requested by xen_hyper_cmd_doms().
*/
static void
xen_hyper_do_doms(struct xen_hyper_cmd_args *da)
{
struct xen_hyper_domain_context *dca;
char buf1[XEN_HYPER_CMD_BUFSIZE];
char buf2[XEN_HYPER_CMD_BUFSIZE];
int i;
sprintf(buf1, " DID %s ST T ",
mkstring(buf2, VADDR_PRLEN, CENTER|RJUST, "DOMAIN"));
mkstring(&buf1[strlen(buf1)], INT_PRLEN, CENTER|RJUST, "MAXPAGE");
strncat(buf1, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf1)-1);
mkstring(&buf1[strlen(buf1)], INT_PRLEN, CENTER|RJUST, "TOTPAGE");
strncat(buf1, " VCPU ", XEN_HYPER_CMD_BUFSIZE-strlen(buf1)-1);
mkstring(&buf1[strlen(buf1)], VADDR_PRLEN, CENTER|RJUST, "SHARED_I");
strncat(buf1, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf1)-1);
mkstring(&buf1[strlen(buf1)], LONG_PRLEN, CENTER|RJUST, "P2M_MFN");
fprintf(fp, "%s\n", buf1);
if (da->cnt) {
for (i = 0; i < da->cnt; i++) {
xen_hyper_show_doms(da->context[i]);
}
} else {
for (i = 0, dca=xhdt->context_array; i < XEN_HYPER_NR_DOMAINS();
i++, dca++) {
xen_hyper_show_doms(dca);
}
}
}
static void
xen_hyper_show_doms(struct xen_hyper_domain_context *dc)
{
char *act, *crash;
uint cpuid;
int type, i, j;
struct xen_hyper_pcpu_context *pcc;
#if defined(X86) || defined(X86_64)
char *shared_info;
#elif defined(IA64)
char *domain_struct;
ulong pgd;
#endif
char buf1[XEN_HYPER_CMD_BUFSIZE];
char buf2[XEN_HYPER_CMD_BUFSIZE];
if (!(dc->domain)) {
return;
}
#if defined(X86) || defined(X86_64)
shared_info = GETBUF(XEN_HYPER_SIZE(shared_info));
if (dc->shared_info) {
if (!readmem(dc->shared_info, KVADDR, shared_info,
XEN_HYPER_SIZE(shared_info), "fill_shared_info_struct",
ACTIVE() ? (RETURN_ON_ERROR|QUIET) : RETURN_ON_ERROR)) {
error(WARNING, "cannot fill shared_info struct.\n");
BZERO(shared_info, XEN_HYPER_SIZE(shared_info));
}
}
#elif defined(IA64)
if ((domain_struct = xen_hyper_read_domain(dc->domain)) == NULL) {
error(FATAL, "cannot read domain.\n");
}
#endif
act = NULL;
for_cpu_indexes(i, cpuid)
{
pcc = xen_hyper_id_to_pcpu_context(cpuid);
for (j = 0; j < dc->vcpu_cnt; j++) {
if (pcc->current_vcpu == dc->vcpu[j]) {
act = ">";
break;
}
}
if (act) break;
}
if (act == NULL) act = " ";
if (xht->crashing_vcc && dc->domain == xht->crashing_vcc->domain) {
crash = "*";
} else {
crash = " ";
}
sprintf(buf1, "%s%s%5d ", act, crash, dc->domain_id);
mkstring(&buf1[strlen(buf1)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, (char *)(dc->domain));
strncat(buf1, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf1)-1);
sprintf(&buf1[strlen(buf1)], "%s ",
xen_hyper_domain_state_string(dc, buf2, !VERBOSE));
sprintf(&buf1[strlen(buf1)], "%s ",
xen_hyper_domain_context_to_type(dc, &type, buf2, !VERBOSE));
mkstring(&buf1[strlen(buf1)], INT_PRLEN, CENTER|INT_HEX|RJUST,
MKSTR((long)(dc->max_pages)));
strncat(buf1, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf1)-1);
mkstring(&buf1[strlen(buf1)], INT_PRLEN, CENTER|INT_HEX|RJUST,
MKSTR((long)(dc->tot_pages)));
sprintf(&buf1[strlen(buf1)], " %3d ", dc->vcpu_cnt);
mkstring(&buf1[strlen(buf1)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(dc->shared_info));
strncat(buf1, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf1)-1);
#if defined(X86) || defined(X86_64)
if (dc->shared_info) {
mkstring(&buf1[strlen(buf1)], LONG_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(ULONG(shared_info +
XEN_HYPER_OFFSET(shared_info_arch) +
XEN_HYPER_OFFSET(arch_shared_info_pfn_to_mfn_frame_list_list)))
);
} else {
mkstring(&buf1[strlen(buf1)], LONG_PRLEN, CENTER|RJUST, "----");
}
FREEBUF(shared_info);
#elif defined(IA64)
pgd = ULONG(domain_struct + XEN_HYPER_OFFSET(domain_arch) +
XEN_HYPER_OFFSET(arch_domain_mm) +
XEN_HYPER_OFFSET(mm_struct_pgd));
if (pgd) {
mkstring(&buf1[strlen(buf1)], LONG_PRLEN,
CENTER|LONG_HEX|RJUST,
MKSTR((pgd - DIRECTMAP_VIRT_START) >> machdep->pageshift));
} else {
mkstring(&buf1[strlen(buf1)], LONG_PRLEN, CENTER|RJUST, "----");
}
#endif
fprintf(fp, "%s\n", buf1);
}
/*
* Display ELF Notes information.
*/
void
xen_hyper_cmd_dumpinfo(void)
{
struct xen_hyper_cmd_args dia;
ulong flag;
ulong val;
struct xen_hyper_dumpinfo_context *dic;
int c, cnt, type, bogus;
BZERO(&dia, sizeof(struct xen_hyper_cmd_args));
flag = val =0;
dic = NULL;
while ((c = getopt(argcnt, args, "rt")) != EOF) {
switch(c)
{
case 't':
flag |= XEN_HYPER_DUMPINFO_TIME;
break;
case 'r':
flag |= XEN_HYPER_DUMPINFO_REGS;
break;
default:
argerrs++;
break;
}
}
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
cnt = bogus = 0;
while (args[optind]) {
if (IS_A_NUMBER(args[optind])) {
type = xen_hyper_str_to_dumpinfo_context(args[optind], &val, &dic);
switch (type)
{
case XEN_HYPER_STR_PCID:
case XEN_HYPER_STR_ADDR:
dia.value[cnt] = val;
dia.type[cnt] = type;
dia.context[cnt] = dic;
cnt++;
break;
case XEN_HYPER_STR_INVALID:
error(INFO, "invalid note address or id "
"value: %s\n\n", args[optind]);
bogus++;
break;
}
} else {
error(INFO, "invalid note address or id "
"value: %s\n\n", args[optind]);
}
optind++;
}
dia.cnt = cnt;
if (!cnt && bogus) {
return;
}
xen_hyper_do_dumpinfo(flag, &dia);
}
/*
* Do the work requested by xen_hyper_cmd_dumpinfo().
*/
static void
xen_hyper_do_dumpinfo(ulong flag, struct xen_hyper_cmd_args *dia)
{
struct xen_hyper_dumpinfo_context *dic;
char buf[XEN_HYPER_CMD_BUFSIZE];
int i, cnt;
if (dia->cnt) {
cnt = dia->cnt;
} else {
cnt = XEN_HYPER_NR_PCPUS();
}
for (i = 0; i < cnt; i++) {
if (i == 0 || flag & XEN_HYPER_DUMPINFO_REGS ||
flag & XEN_HYPER_DUMPINFO_TIME) {
if (i) {
fprintf(fp, "\n");
}
sprintf(buf, " PCID ");
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "ENOTE");
// sprintf(&buf[strlen(buf)], " PID PPID PGRP SID");
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "CORE");
if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V2) {
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "XEN_CORE");
}
if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V3) {
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "XEN_INFO");
}
fprintf(fp, "%s\n", buf);
}
if (dia->cnt) {
dic = dia->context[i];
} else {
dic = xen_hyper_id_to_dumpinfo_context(xht->cpu_idxs[i]);
}
xen_hyper_show_dumpinfo(flag, dic);
}
}
static void
xen_hyper_show_dumpinfo(ulong flag, struct xen_hyper_dumpinfo_context *dic)
{
char buf[XEN_HYPER_CMD_BUFSIZE];
char *note_buf;
ulong addr;
ulong *regs;
long tv_sec, tv_usec;
int i, regcnt;
if (!dic || !dic->note) {
return;
}
note_buf = dic->ELF_Prstatus_ptr;
sprintf(buf, "%5d ", dic->pcpu_id);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(dic->note));
#if 0
pid = INT(note_buf + XEN_HYPER_OFFSET(ELF_Prstatus_pr_pid));
sprintf(&buf[strlen(buf)], " %5d ", pid);
pid = INT(note_buf + XEN_HYPER_OFFSET(ELF_Prstatus_pr_ppid));
sprintf(&buf[strlen(buf)], "%5d ", pid);
pid = INT(note_buf + XEN_HYPER_OFFSET(ELF_Prstatus_pr_pgrp));
sprintf(&buf[strlen(buf)], "%5d ", pid);
pid = INT(note_buf + XEN_HYPER_OFFSET(ELF_Prstatus_pr_sid));
sprintf(&buf[strlen(buf)], "%5d", pid);
#endif
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(dic->note));
if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V2) {
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(dic->note + xhdit->core_size));
}
if (xhdit->note_ver >= XEN_HYPER_ELF_NOTE_V3) {
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
if (xhdit->xen_info_cpu == dic->pcpu_id)
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(dic->note + xhdit->core_size + xhdit->xen_core_size));
else
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "--");
}
fprintf(fp, "%s\n", buf);
if (flag & XEN_HYPER_DUMPINFO_TIME) {
sprintf(buf, " ");
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "tv_sec");
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "tv_usec");
fprintf(fp, "%s\n", buf);
addr = (ulong)note_buf +
XEN_HYPER_OFFSET(ELF_Prstatus_pr_utime);
for (i = 0; i < 4; i++, addr += XEN_HYPER_SIZE(ELF_Timeval)) {
switch (i)
{
case 0:
sprintf(buf, " pr_utime ");
break;
case 1:
sprintf(buf, " pr_stime ");
break;
case 2:
sprintf(buf, " pr_cutime ");
break;
case 3:
sprintf(buf, " pr_cstime ");
break;
}
tv_sec = LONG(addr +
XEN_HYPER_OFFSET(ELF_Timeval_tv_sec));
tv_usec = LONG(addr +
XEN_HYPER_OFFSET(ELF_Timeval_tv_sec) +
XEN_HYPER_OFFSET(ELF_Timeval_tv_usec));
mkstring(&buf[strlen(buf)], LONG_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(tv_sec));
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], LONG_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(tv_usec));
fprintf(fp, "%s\n", buf);
}
}
if (flag & XEN_HYPER_DUMPINFO_REGS) {
regcnt = XEN_HYPER_SIZE(ELF_Gregset) / sizeof(long);
addr = (ulong)note_buf +
XEN_HYPER_OFFSET(ELF_Prstatus_pr_reg);
regs = (ulong *)addr;
fprintf(fp, "Register information(%lx):\n",
dic->note + xhdit->core_offset + XEN_HYPER_OFFSET(ELF_Prstatus_pr_reg));
for (i = 0; i < regcnt; i++, regs++) {
if (xhregt[i] == NULL) {
break;
}
fprintf(fp, " %s = ", xhregt[i]);
fprintf(fp, "0x%s\n",
mkstring(buf, LONG_PRLEN, LONG_HEX|LJUST, MKSTR(*regs)));
}
}
}
/*
* Dump the Xen conring in chronological order.
*/
void
xen_hyper_cmd_log(void)
{
int c;
while ((c = getopt(argcnt, args, "")) != EOF) {
switch(c)
{
default:
argerrs++;
break;
}
}
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
xen_hyper_dump_log();
}
void
xen_hyper_dump_log(void)
{
uint conringp, warp, len, idx, i;
ulong conring;
char *buf;
char last = 0;
uint32_t conring_size;
if (get_symbol_type("conring", NULL, NULL) == TYPE_CODE_ARRAY)
conring = symbol_value("conring");
else
get_symbol_data("conring", sizeof(ulong), &conring);
get_symbol_data("conringp", sizeof(uint), &conringp);
if (symbol_exists("conring_size"))
get_symbol_data("conring_size", sizeof(uint32_t), &conring_size);
else
conring_size = XEN_HYPER_CONRING_SIZE;
if (conringp >= conring_size) {
idx = conringp & (conring_size - 1);
len = conring_size;
warp = TRUE;
} else {
idx = 0;
len = conringp;
warp = FALSE;
}
buf = GETBUF(conring_size);
readmem(conring, KVADDR, buf, conring_size,
"conring contents", FAULT_ON_ERROR);
wrap_around:
for (i = idx; i < len; i++) {
if (buf[i]) {
fputc(ascii(buf[i]) ? buf[i] : '.', fp);
last = buf[i];
}
}
if (warp) {
len = idx;
idx = 0;
warp = FALSE;
goto wrap_around;
}
if (last != '\n') {
fprintf(fp, "\n");
}
FREEBUF(buf);
}
/*
* Display physical cpu information.
*/
void
xen_hyper_cmd_pcpus(void)
{
struct xen_hyper_cmd_args pca;
struct xen_hyper_pcpu_context *pcc;
ulong flag;
ulong val;
int c, cnt, type, bogus;
BZERO(&pca, sizeof(struct xen_hyper_cmd_args));
flag= 0;
while ((c = getopt(argcnt, args, "rt")) != EOF) {
switch(c)
{
case 'r':
flag |= XEN_HYPER_PCPUS_REGS;
break;
case 't':
flag |= XEN_HYPER_PCPUS_TSS;
break;
default:
argerrs++;
break;
}
}
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
cnt = bogus = 0;
while (args[optind]) {
if (IS_A_NUMBER(args[optind])) {
type = xen_hyper_str_to_pcpu_context(args[optind], &val, &pcc);
switch (type) {
case XEN_HYPER_STR_PCID:
case XEN_HYPER_STR_PCPU:
pca.value[cnt] = val;
pca.type[cnt] = type;
pca.addr[cnt] = pcc->pcpu;
pca.context[cnt] = pcc;
cnt++;
break;
case XEN_HYPER_STR_INVALID:
error(INFO, "invalid pcpu or id value: %s\n\n",
args[optind]);
bogus++;
}
} else {
error(FATAL, "invalid address: %s\n",
args[optind]);
}
optind++;
}
pca.cnt = cnt;
if (bogus && !cnt) {
return;
}
xen_hyper_do_pcpus(flag, &pca);
}
/*
* Do the work requested by xen_hyper_cmd_pcpu().
*/
static void
xen_hyper_do_pcpus(ulong flag, struct xen_hyper_cmd_args *pca)
{
struct xen_hyper_pcpu_context *pcc;
uint cpuid;
int i;
if (pca->cnt) {
for (i = 0; i < pca->cnt; i++) {
xen_hyper_show_pcpus(flag, pca->context[i]);
flag |= XEN_HYPER_PCPUS_1STCALL;
}
} else {
for_cpu_indexes(i, cpuid)
{
pcc = xen_hyper_id_to_pcpu_context(cpuid);
xen_hyper_show_pcpus(flag, pcc);
flag |= XEN_HYPER_PCPUS_1STCALL;
}
}
}
static void
xen_hyper_show_pcpus(ulong flag, struct xen_hyper_pcpu_context *pcc)
{
char *act = " ";
char buf[XEN_HYPER_CMD_BUFSIZE];
if (!(pcc->pcpu)) {
return;
}
if (XEN_HYPER_CRASHING_CPU() == pcc->processor_id) {
act = " *";
}
if ((flag & XEN_HYPER_PCPUS_REGS) || (flag & XEN_HYPER_PCPUS_TSS) ||
!(flag & XEN_HYPER_PCPUS_1STCALL)) {
if (((flag & XEN_HYPER_PCPUS_REGS) || (flag & XEN_HYPER_PCPUS_TSS)) &&
(flag & XEN_HYPER_PCPUS_1STCALL)) {
fprintf(fp, "\n");
}
sprintf(buf, " PCID ");
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "PCPU");
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "CUR-VCPU");
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "TSS");
fprintf(fp, "%s\n", buf);
}
sprintf(buf, "%s%5d ", act, pcc->processor_id);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST, MKSTR(pcc->pcpu));
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(pcc->current_vcpu));
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(pcc->init_tss));
fprintf(fp, "%s\n", buf);
if (flag & XEN_HYPER_PCPUS_REGS) {
fprintf(fp, "Register information:\n");
dump_struct("cpu_user_regs", pcc->guest_cpu_user_regs, 0);
}
if (flag & XEN_HYPER_PCPUS_TSS) {
fprintf(fp, "init_tss information:\n");
dump_struct("tss_struct", pcc->init_tss, 0);
}
}
/*
* Display schedule info.
*/
void
xen_hyper_cmd_sched(void)
{
struct xen_hyper_cmd_args scha;
struct xen_hyper_pcpu_context *pcc;
ulong flag;
ulong val;
int c, cnt, type, bogus;
BZERO(&scha, sizeof(struct xen_hyper_cmd_args));
flag = 0;
while ((c = getopt(argcnt, args, "v")) != EOF) {
switch(c)
{
case 'v':
flag |= XEN_HYPER_SCHED_VERBOSE;
break;
default:
argerrs++;
break;
}
}
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
cnt = bogus = 0;
while (args[optind]) {
if (IS_A_NUMBER(args[optind])) {
type = xen_hyper_str_to_pcpu_context(args[optind], &val, &pcc);
switch (type) {
case XEN_HYPER_STR_PCID:
scha.value[cnt] = val;
scha.type[cnt] = type;
scha.context[cnt] = &xhscht->sched_context_array[val];
cnt++;
break;
case XEN_HYPER_STR_PCPU:
case XEN_HYPER_STR_INVALID:
error(INFO, "invalid pcpu id value: %s\n\n",
args[optind]);
bogus++;
}
} else {
error(FATAL, "invalid address: %s\n",
args[optind]);
}
optind++;
}
scha.cnt = cnt;
if (bogus && !cnt) {
return;
}
xen_hyper_do_sched(flag, &scha);
}
/*
* Do the work requested by xen_hyper_cmd_pcpu().
*/
static void
xen_hyper_do_sched(ulong flag, struct xen_hyper_cmd_args *scha)
{
struct xen_hyper_sched_context *schc;
uint cpuid;
int i;
fprintf(fp, "Scheduler name : %s\n\n", xhscht->name);
if (scha->cnt) {
for (i = 0; i < scha->cnt; i++) {
xen_hyper_show_sched(flag, scha->context[i]);
flag |= XEN_HYPER_SCHED_1STCALL;
}
} else {
for_cpu_indexes(i, cpuid)
{
schc = &xhscht->sched_context_array[cpuid];
xen_hyper_show_sched(flag, schc);
flag |= XEN_HYPER_SCHED_1STCALL;
}
}
}
static void
xen_hyper_show_sched(ulong flag, struct xen_hyper_sched_context *schc)
{
char buf[XEN_HYPER_CMD_BUFSIZE];
if (!(schc->schedule_data)) {
return;
}
if ((flag & XEN_HYPER_SCHED_VERBOSE) ||
!(flag & XEN_HYPER_SCHED_1STCALL)) {
if ((flag & XEN_HYPER_SCHED_1STCALL) &&
(flag & XEN_HYPER_SCHED_VERBOSE)) {
fprintf(fp, "\n");
}
sprintf(buf, " CPU ");
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "SCH-DATA");
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "SCH-PRIV");
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "CUR-VCPU");
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|RJUST, "IDL-VCPU");
if (XEN_HYPER_VALID_MEMBER(schedule_data_tick)) {
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], LONG_PRLEN, CENTER|RJUST, "TICK");
}
fprintf(fp, "%s\n", buf);
}
sprintf(buf, "%5d ", schc->cpu_id);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(schc->schedule_data));
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(schc->sched_priv));
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(schc->curr));
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(schc->idle));
if (XEN_HYPER_VALID_MEMBER(schedule_data_tick)) {
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
mkstring(&buf[strlen(buf)], LONG_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(schc->tick));
}
fprintf(fp, "%s\n", buf);
if (flag & XEN_HYPER_SCHED_VERBOSE) {
;
}
}
/*
* Display general system info.
*/
void
xen_hyper_cmd_sys(void)
{
int c;
ulong sflag;
sflag = FALSE;
while ((c = getopt(argcnt, args, "c")) != EOF) {
switch(c)
{
case 'c':
sflag = TRUE;
break;
default:
argerrs++;
break;
}
}
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
if (!args[optind]) {
if (sflag)
fprintf(fp, "No support argument\n");
/* display config info here. */
else
xen_hyper_display_sys_stats();
return;
}
}
/*
* Display system stats at init-time or for the sys command.
*/
void
xen_hyper_display_sys_stats(void)
{
struct new_utsname *uts;
char buf1[XEN_HYPER_CMD_BUFSIZE];
char buf2[XEN_HYPER_CMD_BUFSIZE];
ulong mhz;
int len, flag;
uts = &xht->utsname;
len = 11;
flag = XEN_HYPER_PRI_R;
/*
* It's now safe to unlink the remote namelist.
*/
if (pc->flags & UNLINK_NAMELIST) {
unlink(pc->namelist);
pc->flags &= ~UNLINK_NAMELIST;
pc->flags |= NAMELIST_UNLINKED;
}
if (REMOTE()) {
switch (pc->flags &
(NAMELIST_LOCAL|NAMELIST_UNLINKED|NAMELIST_SAVED))
{
case NAMELIST_UNLINKED:
XEN_HYPER_PRI(fp, len, "KERNEL: ", buf1, flag,
(buf1, "%s (temporary)\n", pc->namelist));
break;
case (NAMELIST_UNLINKED|NAMELIST_SAVED):
case NAMELIST_LOCAL:
XEN_HYPER_PRI(fp, len, "KERNEL: ", buf1, flag,
(buf1, "%s\n", pc->namelist));
break;
}
} else {
if (pc->system_map) {
XEN_HYPER_PRI(fp, len, "SYSTEM MAP: ", buf1, flag,
(buf1, "%s\n", pc->system_map));
XEN_HYPER_PRI(fp, len, "DEBUG KERNEL: ", buf1, flag,
(buf1, "%s\n", pc->namelist));
} else {
XEN_HYPER_PRI(fp, len, "KERNEL: ", buf1, flag,
(buf1, "%s\n", pc->namelist));
}
}
if (pc->debuginfo_file) {
XEN_HYPER_PRI(fp, len, "DEBUGINFO: ", buf1, flag,
(buf1, "%s\n", pc->debuginfo_file));
} else if (pc->namelist_debug) {
XEN_HYPER_PRI(fp, len, "DEBUG KERNEL: ", buf1, flag,
(buf1, "%s\n", pc->namelist_debug));
}
XEN_HYPER_PRI_CONST(fp, len, "DUMPFILE: ", flag);
if (ACTIVE()) {
if (REMOTE_ACTIVE())
fprintf(fp, "%s@%s (remote live system)\n",
pc->server_memsrc, pc->server);
else
fprintf(fp, "%s\n", pc->live_memsrc);
} else {
if (REMOTE_DUMPFILE())
fprintf(fp, "%s@%s (remote dumpfile)",
pc->server_memsrc, pc->server);
else
fprintf(fp, "%s", pc->dumpfile);
fprintf(fp, "\n");
}
XEN_HYPER_PRI(fp, len, "CPUS: ", buf1, flag,
(buf1, "%d\n", XEN_HYPER_NR_PCPUS()));
XEN_HYPER_PRI(fp, len, "DOMAINS: ", buf1, flag,
(buf1, "%d\n", XEN_HYPER_NR_DOMAINS()));
/* !!!Display a date here if it can be found. */
XEN_HYPER_PRI(fp, len, "UPTIME: ", buf1, flag,
(buf1, "%s\n", (xen_hyper_get_uptime_hyper() ?
convert_time(xen_hyper_get_uptime_hyper(), buf2) : "--:--:--")));
/* !!!Display a version here if it can be found. */
XEN_HYPER_PRI_CONST(fp, len, "MACHINE: ", flag);
if (strlen(uts->machine)) {
fprintf(fp, "%s ", uts->machine);
} else {
fprintf(fp, "unknown ");
}
if ((mhz = machdep->processor_speed()))
fprintf(fp, "(%ld Mhz)\n", mhz);
else
fprintf(fp, "(unknown Mhz)\n");
XEN_HYPER_PRI(fp, len, "MEMORY: ", buf1, flag,
(buf1, "%s\n", get_memory_size(buf2)));
if (XENDUMP_DUMPFILE() && (kt->xen_flags & XEN_SUSPEND))
return;
}
/*
* Display vcpu struct.
*/
void
xen_hyper_cmd_vcpu(void)
{
struct xen_hyper_cmd_args vca;
struct xen_hyper_vcpu_context *vcc;
ulong flag;
ulong valvc, valdom;
int c, cnt, type, bogus;
BZERO(&vca, sizeof(struct xen_hyper_cmd_args));
flag = 0;
while ((c = getopt(argcnt, args, "i")) != EOF) {
switch(c)
{
case 'i':
flag |= XEN_HYPER_VCPUS_ID;
break;
default:
argerrs++;
break;
}
}
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
cnt = bogus = 0;
while (args[optind]) {
if (IS_A_NUMBER(args[optind])) {
if (flag & XEN_HYPER_VCPUS_ID) {
type = xen_hyper_strid_to_vcpu_context(
args[optind], args[optind+1],
&valdom, &valvc, &vcc);
} else {
type = xen_hyper_strvcpu_to_vcpu_context(
args[optind], &valvc, &vcc);
}
switch (type) {
case XEN_HYPER_STR_VCID:
case XEN_HYPER_STR_VCPU:
vca.value[cnt] = valvc;
vca.type[cnt] = type;
vca.addr[cnt] = vcc->vcpu;
vca.context[cnt] = vcc;
cnt++;
break;
case XEN_HYPER_STR_INVALID:
error(INFO, "invalid vcpu or id value: %s\n\n",
args[optind]);
bogus++;
}
} else {
error(FATAL, "invalid address: %s\n",
args[optind]);
}
optind++;
if (flag & XEN_HYPER_VCPUS_ID) optind++;
}
vca.cnt = cnt;
if (bogus && !cnt) {
return;
}
xen_hyper_do_vcpu(&vca);
}
/*
* Do the work requested by xen_hyper_cmd_vcpu().
*/
static void
xen_hyper_do_vcpu(struct xen_hyper_cmd_args *vca)
{
int i;
if (vca->cnt) {
if (vca->cnt == 1) {
xhvct->last = vca->context[0];
}
for (i = 0; i < vca->cnt; i++) {
dump_struct("vcpu", vca->addr[i], 0);
}
} else {
dump_struct("vcpu", xhvct->last->vcpu, 0);
}
}
/*
* Display vcpu status.
*/
void
xen_hyper_cmd_vcpus(void)
{
struct xen_hyper_cmd_args vca;
struct xen_hyper_vcpu_context *vcc;
ulong flag;
ulong valvc, valdom;
int c, cnt, type, bogus;
BZERO(&vca, sizeof(struct xen_hyper_cmd_args));
flag = 0;
while ((c = getopt(argcnt, args, "i")) != EOF) {
switch(c)
{
case 'i':
flag |= XEN_HYPER_VCPUS_ID;
break;
default:
argerrs++;
break;
}
}
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
cnt = bogus = 0;
while (args[optind]) {
if (IS_A_NUMBER(args[optind])) {
if (flag & XEN_HYPER_VCPUS_ID) {
type = xen_hyper_strid_to_vcpu_context(
args[optind], args[optind+1],
&valdom, &valvc, &vcc);
} else {
type = xen_hyper_strvcpu_to_vcpu_context(
args[optind], &valvc, &vcc);
}
switch (type) {
case XEN_HYPER_STR_VCID:
case XEN_HYPER_STR_VCPU:
vca.value[cnt] = valvc;
vca.type[cnt] = type;
vca.addr[cnt] = vcc->vcpu;
vca.context[cnt] = vcc;
cnt++;
break;
case XEN_HYPER_STR_INVALID:
error(INFO, "invalid vcpu or id value: %s\n\n",
args[optind]);
bogus++;
}
} else {
error(FATAL, "invalid address: %s\n",
args[optind]);
}
optind++;
}
vca.cnt = cnt;
if (bogus && !cnt) {
return;
}
xen_hyper_do_vcpus(&vca);
}
/*
* Do the work requested by xen_hyper_cmd_vcpus().
*/
static void
xen_hyper_do_vcpus(struct xen_hyper_cmd_args *vca)
{
struct xen_hyper_vcpu_context_array *vcca;
struct xen_hyper_vcpu_context *vcc;
char buf1[XEN_HYPER_CMD_BUFSIZE];
char buf2[XEN_HYPER_CMD_BUFSIZE];
int i, j;
fprintf(fp, " VCID PCID %s ST T DOMID %s\n",
mkstring(buf1, VADDR_PRLEN, CENTER|RJUST, "VCPU"),
mkstring(buf2, VADDR_PRLEN, CENTER|RJUST, "DOMAIN"));
if (vca->cnt) {
for (i = 0; i < vca->cnt; i++) {
xen_hyper_show_vcpus(vca->context[i]);
}
} else {
for (i = 0, vcca = xhvct->vcpu_context_arrays;
i < XEN_HYPER_NR_DOMAINS(); i++, vcca++) {
for (j = 0, vcc = vcca->context_array;
j < vcca->context_array_valid; j++, vcc++) {
xen_hyper_show_vcpus(vcc);
}
}
}
}
static void
xen_hyper_show_vcpus(struct xen_hyper_vcpu_context *vcc)
{
int type;
char *act, *crash;
char buf[XEN_HYPER_CMD_BUFSIZE];
struct xen_hyper_pcpu_context *pcc;
domid_t domid;
if (!(vcc->vcpu)) {
return;
}
if((pcc = xen_hyper_id_to_pcpu_context(vcc->processor))) {
if (pcc->current_vcpu == vcc->vcpu) {
act = ">";
} else {
act = " ";
}
} else {
act = " ";
}
if (xht->crashing_vcc && vcc->vcpu == xht->crashing_vcc->vcpu) {
crash = "*";
} else {
crash = " ";
}
sprintf(buf, "%s%s%5d %5d ", act, crash, vcc->vcpu_id, vcc->processor);
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(vcc->vcpu));
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
xen_hyper_vcpu_state_string(vcc, &buf[strlen(buf)], !VERBOSE);
strncat(buf, " ", XEN_HYPER_CMD_BUFSIZE-strlen(buf)-1);
xen_hyper_domain_to_type(vcc->domain, &type, &buf[strlen(buf)], !VERBOSE);
if ((domid = xen_hyper_domain_to_id(vcc->domain)) == XEN_HYPER_DOMAIN_ID_INVALID) {
sprintf(&buf[strlen(buf)], " ????? ");
} else {
sprintf(&buf[strlen(buf)], " %5d ", domid);
}
mkstring(&buf[strlen(buf)], VADDR_PRLEN, CENTER|LONG_HEX|RJUST,
MKSTR(vcc->domain));
fprintf(fp, "%s\n", buf);
}
/*
* Get string for domain status.
* - This may need some data in domain struct.
*/
char *
xen_hyper_domain_state_string(struct xen_hyper_domain_context *dc,
char *buf, int verbose)
{
ulong stat;
stat = xen_hyper_domain_state(dc);
if (stat == XEN_HYPER_DOMF_ERROR) {
sprintf(buf, verbose ? "(unknown)" : "??");
} else if (XEN_HYPER_VALID_MEMBER(domain_domain_flags)) {
if (stat & XEN_HYPER_DOMF_shutdown) {
sprintf(buf, verbose ? "DOMAIN_SHUTDOWN" : "SF");
} else if (stat & XEN_HYPER_DOMF_dying) {
sprintf(buf, verbose ? "DOMAIN_DYING" : "DY");
} else if (stat & XEN_HYPER_DOMF_ctrl_pause) {
sprintf(buf, verbose ? "DOMAIN_CTRL_PAUSE" : "CP");
} else if (stat & XEN_HYPER_DOMF_polling) {
sprintf(buf, verbose ? "DOMAIN_POLLING" : "PO");
} else if (stat & XEN_HYPER_DOMF_paused) {
sprintf(buf, verbose ? "DOMAIN_PAUSED" : "PA");
} else {
sprintf(buf, verbose ? "DOMAIN_RUNNING" : "RU");
}
} else {
if (stat & XEN_HYPER_DOMS_shutdown) {
sprintf(buf, verbose ? "DOMAIN_SHUTDOWN" : "SF");
} else if (stat & XEN_HYPER_DOMS_shuttingdown) {
sprintf(buf, verbose ? "DOMAIN_SHUTTINGDOWN" : "SH");
} else if (stat & XEN_HYPER_DOMS_dying) {
sprintf(buf, verbose ? "DOMAIN_DYING" : "DY");
} else if (stat & XEN_HYPER_DOMS_ctrl_pause) {
sprintf(buf, verbose ? "DOMAIN_CTRL_PAUSE" : "CP");
} else if (stat & XEN_HYPER_DOMS_polling) {
sprintf(buf, verbose ? "DOMAIN_POLLING" : "PO");
} else {
sprintf(buf, verbose ? "DOMAIN_RUNNING" : "RU");
}
}
return buf;
}
/*
* Get string for vcpu status.
* - This may need some data in vcpu struct.
*/
char *
xen_hyper_vcpu_state_string(struct xen_hyper_vcpu_context *vcc,
char *buf, int verbose)
{
int stat;
stat = xen_hyper_vcpu_state(vcc);
if (stat == XEN_HYPER_RUNSTATE_ERROR) {
sprintf(buf, verbose ? "(unknown)" : "??");
} else if (stat == XEN_HYPER_RUNSTATE_running ||
stat == XEN_HYPER_RUNSTATE_runnable) {
sprintf(buf, verbose ? "VCPU_RUNNING" : "RU");
} else if (stat == XEN_HYPER_RUNSTATE_blocked) {
sprintf(buf, verbose ? "VCPU_BLOCKED" : "BL");
} else if (stat == XEN_HYPER_RUNSTATE_offline) {
sprintf(buf, verbose ? "VCPU_OFFLINE" : "OF");
} else {
sprintf(buf, verbose ? "(unknown)" : "??");
}
return buf;
}
/*
* Get domain type from domain address.
*/
static char *
xen_hyper_domain_to_type(ulong domain, int *type, char *buf, int verbose)
{
struct xen_hyper_domain_context *dc;
if ((dc = xen_hyper_domain_to_domain_context(domain)) == NULL) {
error(WARNING, "cannot get context from domain address.\n");
return NULL;
}
return xen_hyper_domain_context_to_type(dc, type, buf, verbose);
}
/*
* Get domain type from domain context.
*/
static char *
xen_hyper_domain_context_to_type(struct xen_hyper_domain_context *dc, int *type,
char *buf, int verbose)
{
if (!dc) {
*type = XEN_HYPER_DOMAIN_TYPE_INVALID;
return NULL;
} else if (dc->domain_id == XEN_HYPER_DOMID_IO) {
*type = XEN_HYPER_DOMAIN_TYPE_IO;
sprintf(buf, verbose ? "dom_io" : "O");
} else if (dc->domain_id == XEN_HYPER_DOMID_XEN) {
*type = XEN_HYPER_DOMAIN_TYPE_XEN;
sprintf(buf, verbose ? "dom_xen" : "X");
} else if (dc->domain_id == XEN_HYPER_DOMID_IDLE) {
*type = XEN_HYPER_DOMAIN_TYPE_IDLE;
sprintf(buf, verbose ? "idle domain" : "I");
} else if (dc == xhdt->dom0) {
*type = XEN_HYPER_DOMAIN_TYPE_DOM0;
sprintf(buf, verbose ? "domain 0" : "0");
} else {
*type = XEN_HYPER_DOMAIN_TYPE_GUEST;
sprintf(buf, verbose ? "domain U" : "U");
}
return buf;
}
/*
* Check a type for value. And return domain context.
*/
static int
xen_hyper_str_to_domain_context(char *string, ulong *value,
struct xen_hyper_domain_context **dcp)
{
ulong dvalue, hvalue;
int found, type;
char *s;
struct xen_hyper_domain_context *dc_did, *dc_ddc, *dc_hid, *dc_hdc;
if (string == NULL) {
error(INFO, "received NULL string\n");
return STR_INVALID;
}
s = string;
dvalue = hvalue = BADADDR;
if (decimal(s, 0))
dvalue = dtol(s, RETURN_ON_ERROR, NULL);
if (hexadecimal(s, 0)) {
if (STRNEQ(s, "0x") || STRNEQ(s, "0X"))
s += 2;
if (strlen(s) <= MAX_HEXADDR_STRLEN)
hvalue = htol(s, RETURN_ON_ERROR, NULL);
}
found = 0;
dc_did = dc_ddc = dc_hid = dc_hdc = NULL;
type = XEN_HYPER_STR_INVALID;
if (dvalue != BADADDR) {
if ((dc_did = xen_hyper_id_to_domain_context(dvalue)))
found++;
if ((dc_ddc = xen_hyper_domain_to_domain_context(dvalue)))
found++;
}
if ((hvalue != BADADDR) && (dvalue != hvalue)) {
if ((dc_hid = xen_hyper_id_to_domain_context(hvalue)))
found++;
if ((dc_hdc = xen_hyper_domain_to_domain_context(hvalue)))
found++;
}
switch (found)
{
case 2:
if (dc_did && dc_hid) {
*dcp = dc_did;
*value = dvalue;
type = STR_PID;
}
break;
case 1:
if (dc_did) {
*dcp = dc_did;
*value = dvalue;
type = XEN_HYPER_STR_DID;
}
if (dc_ddc) {
*dcp = dc_ddc;
*value = dvalue;
type = XEN_HYPER_STR_DOMAIN;
}
if (dc_hid) {
*dcp = dc_hid;
*value = hvalue;
type = XEN_HYPER_STR_DID;
}
if (dc_hdc) {
*dcp = dc_hdc;
*value = hvalue;
type = XEN_HYPER_STR_DOMAIN;
}
break;
}
return type;
}
/*
* Display a vcpu context.
*/
void
xen_hyper_show_vcpu_context(struct xen_hyper_vcpu_context *vcc)
{
char buf[XEN_HYPER_CMD_BUFSIZE];
struct xen_hyper_pcpu_context *pcc;
struct xen_hyper_domain_context *dc;
int len, flag;
len = 6;
len += pc->flags & RUNTIME ? 0 : 5;
flag = XEN_HYPER_PRI_R;
if (!(pcc = xen_hyper_id_to_pcpu_context(vcc->processor))) {
error(WARNING, "cannot get pcpu context vcpu belongs.\n");
return;
}
if (!(dc = xen_hyper_domain_to_domain_context(vcc->domain))) {
error(WARNING, "cannot get domain context vcpu belongs.\n");
return;
}
XEN_HYPER_PRI(fp, len, "PCPU-ID: ", buf, flag,
(buf, "%d\n", vcc->processor));
XEN_HYPER_PRI(fp, len, "PCPU: ", buf, flag,
(buf, "%lx\n", pcc->pcpu));
XEN_HYPER_PRI(fp, len, "VCPU-ID: ", buf, flag,
(buf, "%d\n", vcc->vcpu_id));
XEN_HYPER_PRI(fp, len, "VCPU: ", buf, flag,
(buf, "%lx ", vcc->vcpu));
fprintf(fp, "(%s)\n", xen_hyper_vcpu_state_string(vcc, buf, VERBOSE));
XEN_HYPER_PRI(fp, len, "DOMAIN-ID: ", buf, flag,
(buf, "%d\n", dc->domain_id));
XEN_HYPER_PRI(fp, len, "DOMAIN: ", buf, flag,
(buf, "%lx ", vcc->domain));
fprintf(fp, "(%s)\n", xen_hyper_domain_state_string(dc, buf, VERBOSE));
XEN_HYPER_PRI_CONST(fp, len, "STATE: ", flag);
if (machdep->flags & HWRESET) {
fprintf(fp, "HARDWARE RESET");
} else if (machdep->flags & INIT) {
fprintf(fp, "INIT");
} else if (xen_hyper_is_vcpu_crash(vcc)) {
fprintf(fp, "CRASH");
} else {
fprintf(fp, "ACTIVE");
}
fprintf(fp, "\n");
}
/*
* Check a type for value. And return dump information context address.
*/
static int
xen_hyper_str_to_dumpinfo_context(char *string, ulong *value,
struct xen_hyper_dumpinfo_context **dicp)
{
ulong dvalue, hvalue;
struct xen_hyper_dumpinfo_context *note_did, *note_hid;
struct xen_hyper_dumpinfo_context *note_dad, *note_had;
int found, type;
char *s;
if (string == NULL) {
error(INFO, "received NULL string\n");
return STR_INVALID;
}
s = string;
dvalue = hvalue = BADADDR;
if (decimal(s, 0))
dvalue = dtol(s, RETURN_ON_ERROR, NULL);
if (hexadecimal(s, 0)) {
if (STRNEQ(s, "0x") || STRNEQ(s, "0X"))
s += 2;
if (strlen(s) <= MAX_HEXADDR_STRLEN)
hvalue = htol(s, RETURN_ON_ERROR, NULL);
}
found = 0;
note_did = note_hid = note_dad = note_had = 0;
type = XEN_HYPER_STR_INVALID;
if (dvalue != BADADDR) {
if (dvalue > XEN_HYPER_MAX_CPUS()) {
note_dad = xen_hyper_note_to_dumpinfo_context(dvalue);
} else {
note_did = xen_hyper_id_to_dumpinfo_context(dvalue);
}
found++;
}
if ((hvalue != BADADDR)) {
if (hvalue > XEN_HYPER_MAX_CPUS()) {
note_had = xen_hyper_note_to_dumpinfo_context(hvalue);
} else {
note_hid = xen_hyper_id_to_dumpinfo_context(hvalue);
}
found++;
}
switch (found)
{
case 2:
if (note_did && note_hid) {
*value = dvalue;
*dicp = note_did;
type = XEN_HYPER_STR_PCID;
}
break;
case 1:
if (note_did) {
*value = dvalue;
*dicp = note_did;
type = XEN_HYPER_STR_PCID;
}
if (note_hid) {
*value = hvalue;
*dicp = note_hid;
type = XEN_HYPER_STR_PCID;
}
if (note_dad) {
*value = dvalue;
*dicp = note_dad;
type = XEN_HYPER_STR_ADDR;
}
if (note_had) {
*value = hvalue;
*dicp = note_had;
type = XEN_HYPER_STR_ADDR;
}
break;
}
return type;
}
/*
* Check a type for value. And return vcpu context.
*/
static int
xen_hyper_strvcpu_to_vcpu_context(char *string, ulong *value,
struct xen_hyper_vcpu_context **vccp)
{
ulong dvalue, hvalue;
int found, type;
char *s;
struct xen_hyper_vcpu_context *vcc_dvc, *vcc_hvc;
if (string == NULL) {
error(INFO, "received NULL string\n");
return STR_INVALID;
}
s = string;
dvalue = hvalue = BADADDR;
if (decimal(s, 0))
dvalue = dtol(s, RETURN_ON_ERROR, NULL);
if (hexadecimal(s, 0)) {
if (STRNEQ(s, "0x") || STRNEQ(s, "0X"))
s += 2;
if (strlen(s) <= MAX_HEXADDR_STRLEN)
hvalue = htol(s, RETURN_ON_ERROR, NULL);
}
found = 0;
vcc_dvc = vcc_hvc = NULL;
type = XEN_HYPER_STR_INVALID;
if (dvalue != BADADDR) {
if ((vcc_dvc = xen_hyper_vcpu_to_vcpu_context(dvalue)))
found++;
}
if ((hvalue != BADADDR) && (dvalue != hvalue)) {
if ((vcc_hvc = xen_hyper_vcpu_to_vcpu_context(hvalue)))
found++;
}
switch (found)
{
case 1:
if (vcc_dvc) {
*vccp = vcc_dvc;
*value = dvalue;
type = XEN_HYPER_STR_VCPU;
}
if (vcc_hvc) {
*vccp = vcc_hvc;
*value = hvalue;
type = XEN_HYPER_STR_VCPU;
}
break;
}
return type;
}
/*
* Check a type for id value. And return vcpu context.
*/
static int
xen_hyper_strid_to_vcpu_context(char *strdom, char *strvc, ulong *valdom,
ulong *valvc, struct xen_hyper_vcpu_context **vccp)
{
ulong dvalue, hvalue;
int found, type;
char *s;
struct xen_hyper_vcpu_context *vcc_did, *vcc_hid;
struct xen_hyper_domain_context *dc;
if (strdom == NULL || strvc == NULL) {
error(INFO, "received NULL string\n");
return STR_INVALID;
}
if (xen_hyper_str_to_domain_context(strdom, valdom, &dc) ==
XEN_HYPER_STR_INVALID) {
error(INFO, "invalid domain id string.\n");
return STR_INVALID;
}
s = strvc;
dvalue = hvalue = BADADDR;
if (decimal(s, 0))
dvalue = dtol(s, RETURN_ON_ERROR, NULL);
if (hexadecimal(s, 0)) {
if (STRNEQ(s, "0x") || STRNEQ(s, "0X"))
s += 2;
if (strlen(s) <= MAX_HEXADDR_STRLEN)
hvalue = htol(s, RETURN_ON_ERROR, NULL);
}
found = 0;
vcc_did = vcc_hid = NULL;
type = XEN_HYPER_STR_INVALID;
if (dvalue != BADADDR) {
if ((vcc_did = xen_hyper_id_to_vcpu_context(dc->domain,
XEN_HYPER_DOMAIN_ID_INVALID, dvalue)))
found++;
}
if ((hvalue != BADADDR) && (dvalue != hvalue)) {
if ((vcc_hid = xen_hyper_id_to_vcpu_context(dc->domain,
XEN_HYPER_DOMAIN_ID_INVALID, hvalue)))
found++;
}
switch (found)
{
case 2:
if (vcc_did && vcc_hid) {
*vccp = vcc_did;
*valvc = dvalue;
type = XEN_HYPER_STR_VCID;
}
break;
case 1:
if (vcc_did) {
*vccp = vcc_did;
*valvc = dvalue;
type = XEN_HYPER_STR_VCID;
}
if (vcc_hid) {
*vccp = vcc_hid;
*valvc = hvalue;
type = XEN_HYPER_STR_VCID;
}
break;
}
return type;
}
/*
* Check a type for value. And return pcpu context.
*/
static int
xen_hyper_str_to_pcpu_context(char *string, ulong *value,
struct xen_hyper_pcpu_context **pccp)
{
ulong dvalue, hvalue;
int found, type;
char *s;
struct xen_hyper_pcpu_context *pcc_did, *pcc_dpc, *pcc_hid, *pcc_hpc;
if (string == NULL) {
error(INFO, "received NULL string\n");
return STR_INVALID;
}
s = string;
dvalue = hvalue = BADADDR;
if (decimal(s, 0))
dvalue = dtol(s, RETURN_ON_ERROR, NULL);
if (hexadecimal(s, 0)) {
if (STRNEQ(s, "0x") || STRNEQ(s, "0X"))
s += 2;
if (strlen(s) <= MAX_HEXADDR_STRLEN)
hvalue = htol(s, RETURN_ON_ERROR, NULL);
}
found = 0;
pcc_did = pcc_dpc = pcc_hid = pcc_hpc = NULL;
type = XEN_HYPER_STR_INVALID;
if (dvalue != BADADDR) {
if ((pcc_did = xen_hyper_id_to_pcpu_context(dvalue)))
found++;
if ((pcc_dpc = xen_hyper_pcpu_to_pcpu_context(dvalue)))
found++;
}
if ((hvalue != BADADDR) && (dvalue != hvalue)) {
if ((pcc_hid = xen_hyper_id_to_pcpu_context(hvalue)))
found++;
if ((pcc_hpc = xen_hyper_pcpu_to_pcpu_context(hvalue)))
found++;
}
switch (found)
{
case 2:
if (pcc_did && pcc_hid) {
*pccp = pcc_did;
*value = dvalue;
type = STR_PID;
}
break;
case 1:
if (pcc_did) {
*pccp = pcc_did;
*value = dvalue;
type = XEN_HYPER_STR_PCID;
}
if (pcc_dpc) {
*pccp = pcc_dpc;
*value = dvalue;
type = XEN_HYPER_STR_PCPU;
}
if (pcc_hid) {
*pccp = pcc_hid;
*value = hvalue;
type = XEN_HYPER_STR_PCID;
}
if (pcc_hpc) {
*pccp = pcc_hpc;
*value = hvalue;
type = XEN_HYPER_STR_PCPU;
}
break;
}
return type;
}
#endif