Mercurial > hvf > hvf
view cp/shell/cmd_display.c @ 650:6fca4100a886
include: change uint64_t LP64 definition to be unsigned long
This matches what is normally used in the Unix world.
Signed-off-by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
author | Josef 'Jeff' Sipek <jeffpc@josefsipek.net> |
---|---|
date | Tue, 30 Jul 2019 14:56:02 -0400 |
parents | 0a0b076339ca |
children | b482390e2b6b |
line wrap: on
line source
/* * (C) Copyright 2007-2019 Josef 'Jeff' Sipek <jeffpc@josefsipek.net> * * This file is released under the GPLv2. See the COPYING file for more * details. */ static char* parse_addrspec(u64 *val, u64 *len, char *s) { u64 tmp; int parsed = 0; tmp = 0; while(!(*s == '\0' || *s == ' ' || *s == '\t')) { if (*s >= '0' && *s <= '9') tmp = 16*tmp + (*s - '0'); else if ((*s >= 'A' && *s <= 'F') || (*s >= 'a' && *s <= 'f')) tmp = 16*tmp + 10 + ((*s & ~0x20) - 'A'); else if (*s == '.' && parsed) break; else return ERR_PTR(-EINVAL); s++; parsed = 1; } if (len) { *len = 0; if (*s == '.') { s = __extract_hex(s+1, len); if (IS_ERR(s)) parsed = 0; } } *val = tmp; return (parsed == 1 ? s : ERR_PTR(-EINVAL)); } enum display_fmt { FMT_NUMERIC = 0, FMT_INSTRUCT, }; static void __display_storage_instruct(struct virt_sys *sys, u64 guest_addr, u64 mlen) { int ret; char buf[64]; int ilen; u64 val; u64 host_addr; u64 end_addr; /* walk the page tables to find the real page frame */ ret = virt2phy_current(guest_addr, &host_addr); if (ret) { con_printf(sys->con, "DISPLAY: Specified address is not part of " "guest configuration (RC=%d,%d)\n", -EFAULT, ret); return; } if (!mlen) mlen = 1; end_addr = guest_addr + mlen; while(guest_addr < end_addr) { /* * FIXME: make sure crossing page-boundary doesn't break * give us garbage */ ilen = disassm((unsigned char*) host_addr, buf, 64); if ((host_addr & PAGE_MASK) >= (PAGE_SIZE-ilen)) { con_printf(sys->con, "DISPLAY: Instruction spans page " "boundary - not supported\n"); break; } /* load the dword at the address, and shift it to the LSB part */ val = *((u64*)host_addr) >> 8*(sizeof(u64) - ilen); con_printf(sys->con, "R%016lX %0*lX%*s %s\n", guest_addr, 2*ilen, val, /* inst hex dump */ 12-2*ilen, "", /* spacer */ buf); host_addr += ilen; guest_addr += ilen; } } static void __display_storage_numeric(struct virt_sys *sys, u64 guest_addr, u64 mlen) { char buf[80]; char *bp; u64 host_addr; int this_len; int ret; /* round down */ guest_addr &= ~((u64) 0x3); /* walk the page tables to find the real page frame */ ret = virt2phy_current(guest_addr, &host_addr); if (ret) goto fault; if (mlen > 4) mlen = (mlen >> 2) + !!(mlen & 0x3); else mlen = 1; while(mlen && !ret) { this_len = (mlen > 4) ? 4 : mlen; mlen -= this_len; bp = buf; bp += snprintf(bp, 80, "R%016lX ", guest_addr); while(this_len) { bp += snprintf(bp, 80 - (bp - buf), "%08X ", *(u32*)host_addr); guest_addr += 4; host_addr += 4; this_len--; /* loop if we're not crossing a page, or if we're done */ if (((guest_addr & PAGE_MASK) != 0) || !mlen) continue; /* * We will attempt to walk further along guest * storage, and are about to cross a page boundary, * walk the page tables to find the real page frame */ ret = virt2phy_current(guest_addr, &host_addr); if (ret) break; } con_printf(sys->con, "%s\n", buf); } fault: if (ret) con_printf(sys->con, "DISPLAY: The address %016lX is not part of " "guest configuration (RC=%d,%d)\n", guest_addr, -EFAULT, ret); } /* *!!! DISPLAY STORAGE *!! SYNTAX *! \tok{\sc Display} \tok{\sc STOrage} *! \begin{stack} \\ \deftok{N} \\ \tok{I} \end{stack} *! <addr> *! \begin{stack} \\ \tok{.} <length> \end{stack} *!! XATNYS *!! AUTH G *!! PURPOSE *! Displays a portion of guest's storage. *!! OPERANDS *! \cbstart *! \item[addr] is the guest storage address. *! \item[length] is the number of bytes to display. If not specified, 4 is *! assumed. *! \cbend *!! SDNAREPO *!! OPTIONS *! \cbstart *! \item[N] display guest storage in numeric format. *! \item[I] display guest storage in instruction format. *! \cbend *!! SNOITPO *!! NOTES *! \cbstart *! \item Currently, the instruction display does not support page-boundary *! crossing. *! \cbend *!! SETON *!! EXAMPLES *! D STO 200\\ *! D STO N200.10\\ *! D STO I1234.200 */ static int cmd_display_storage(struct virt_sys *sys, char *cmd, int len) { u64 guest_addr; u64 mlen = 0; enum display_fmt fmt; SHELL_CMD_AUTH(sys, G); switch (cmd[0]) { case 'N': case 'n': /* numeric */ cmd++; fmt = FMT_NUMERIC; break; case 'I': case 'i': /* instruction */ cmd++; fmt = FMT_INSTRUCT; break; default: /* numeric */ fmt = FMT_NUMERIC; break; } cmd = parse_addrspec(&guest_addr, &mlen, cmd); if (IS_ERR(cmd)) { con_printf(sys->con, "DISPLAY: Invalid addr-spec\n"); return 0; } if (fmt == FMT_INSTRUCT) __display_storage_instruct(sys, guest_addr, mlen); else __display_storage_numeric(sys, guest_addr, mlen); return 0; } /* *!!! DISPLAY SIECB *!! SYNTAX *! \tok{\sc Display} \tok{\sc SIECB} *!! XATNYS *!! AUTH E *!! PURPOSE *! Displays hexdump of the guest's SIE control block. */ static int cmd_display_siecb(struct virt_sys *sys, char *cmd, int len) { u32 *val; int i; SHELL_CMD_AUTH(sys, E); val = (u32*) &sys->cpu->sie_cb; con_printf(sys->con, "SIECB FOR %s AT %p\n", sys->directory->userid, val); for(i=0; i<(sizeof(struct sie_cb)/sizeof(u32)); i+=4) con_printf(sys->con, "%03lX %08X %08X %08X %08X\n", i*sizeof(u32), val[i], val[i+1], val[i+2], val[i+3]); return 0; } /* *!!! DISPLAY GPR *!! SYNTAX *! \tok{\sc Display} \tok{\sc Gpr} *!! XATNYS *!! AUTH G *!! PURPOSE *! Displays the guest's general purpose registers */ static int cmd_display_gpr(struct virt_sys *sys, char *cmd, int len) { SHELL_CMD_AUTH(sys, G); con_printf(sys->con, "GR 0 = %016lX %016lX\n", sys->cpu->regs.gpr[0], sys->cpu->regs.gpr[1]); con_printf(sys->con, "GR 2 = %016lX %016lX\n", sys->cpu->regs.gpr[2], sys->cpu->regs.gpr[3]); con_printf(sys->con, "GR 4 = %016lX %016lX\n", sys->cpu->regs.gpr[4], sys->cpu->regs.gpr[5]); con_printf(sys->con, "GR 6 = %016lX %016lX\n", sys->cpu->regs.gpr[6], sys->cpu->regs.gpr[7]); con_printf(sys->con, "GR 8 = %016lX %016lX\n", sys->cpu->regs.gpr[8], sys->cpu->regs.gpr[9]); con_printf(sys->con, "GR 10 = %016lX %016lX\n", sys->cpu->regs.gpr[10], sys->cpu->regs.gpr[11]); con_printf(sys->con, "GR 12 = %016lX %016lX\n", sys->cpu->regs.gpr[12], sys->cpu->regs.gpr[13]); con_printf(sys->con, "GR 14 = %016lX %016lX\n", sys->cpu->regs.gpr[14], sys->cpu->regs.gpr[15]); return 0; } /* *!!! DISPLAY FPCR *!! SYNTAX *! \tok{\sc Display} \tok{\sc FPCR} *!! XATNYS *!! AUTH G *!! PURPOSE *! Displays the guest's floating point control register */ static int cmd_display_fpcr(struct virt_sys *sys, char *cmd, int len) { SHELL_CMD_AUTH(sys, G); con_printf(sys->con, "FPCR = %08X\n", sys->cpu->regs.fpcr); return 0; } /* *!!! DISPLAY FPR *!! SYNTAX *! \tok{\sc Display} \tok{\sc Fpr} *!! XATNYS *!! AUTH G *!! PURPOSE *! Displays the guest's floating point registers */ static int cmd_display_fpr(struct virt_sys *sys, char *cmd, int len) { SHELL_CMD_AUTH(sys, G); con_printf(sys->con, "FR 0 = %016lX %016lX\n", sys->cpu->regs.fpr[0], sys->cpu->regs.fpr[1]); con_printf(sys->con, "FR 2 = %016lX %016lX\n", sys->cpu->regs.fpr[2], sys->cpu->regs.fpr[3]); con_printf(sys->con, "FR 4 = %016lX %016lX\n", sys->cpu->regs.fpr[4], sys->cpu->regs.fpr[5]); con_printf(sys->con, "FR 6 = %016lX %016lX\n", sys->cpu->regs.fpr[6], sys->cpu->regs.fpr[7]); con_printf(sys->con, "FR 8 = %016lX %016lX\n", sys->cpu->regs.fpr[8], sys->cpu->regs.fpr[9]); con_printf(sys->con, "FR 10 = %016lX %016lX\n", sys->cpu->regs.fpr[10], sys->cpu->regs.fpr[11]); con_printf(sys->con, "FR 12 = %016lX %016lX\n", sys->cpu->regs.fpr[12], sys->cpu->regs.fpr[13]); con_printf(sys->con, "FR 14 = %016lX %016lX\n", sys->cpu->regs.fpr[14], sys->cpu->regs.fpr[15]); return 0; } /* *!!! DISPLAY CR *!! SYNTAX *! \tok{\sc Display} \tok{\sc Cr} *!! XATNYS *!! AUTH G *!! PURPOSE *! Displays the guest's control registers */ static int cmd_display_cr(struct virt_sys *sys, char *cmd, int len) { SHELL_CMD_AUTH(sys, G); con_printf(sys->con, "CR 0 = %016lX %016lX\n", sys->cpu->sie_cb.gcr[0], sys->cpu->sie_cb.gcr[1]); con_printf(sys->con, "CR 2 = %016lX %016lX\n", sys->cpu->sie_cb.gcr[2], sys->cpu->sie_cb.gcr[3]); con_printf(sys->con, "CR 4 = %016lX %016lX\n", sys->cpu->sie_cb.gcr[4], sys->cpu->sie_cb.gcr[5]); con_printf(sys->con, "CR 6 = %016lX %016lX\n", sys->cpu->sie_cb.gcr[6], sys->cpu->sie_cb.gcr[7]); con_printf(sys->con, "CR 8 = %016lX %016lX\n", sys->cpu->sie_cb.gcr[8], sys->cpu->sie_cb.gcr[9]); con_printf(sys->con, "CR 10 = %016lX %016lX\n", sys->cpu->sie_cb.gcr[10], sys->cpu->sie_cb.gcr[11]); con_printf(sys->con, "CR 12 = %016lX %016lX\n", sys->cpu->sie_cb.gcr[12], sys->cpu->sie_cb.gcr[13]); con_printf(sys->con, "CR 14 = %016lX %016lX\n", sys->cpu->sie_cb.gcr[14], sys->cpu->sie_cb.gcr[15]); return 0; } /* *!!! DISPLAY AR *!! SYNTAX *! \tok{\sc Display} \tok{\sc Ar} *!! XATNYS *!! AUTH G *!! PURPOSE *! Displays the guest's access registers */ static int cmd_display_ar(struct virt_sys *sys, char *cmd, int len) { SHELL_CMD_AUTH(sys, G); con_printf(sys->con, "AR 0 = %08X %08X\n", sys->cpu->regs.ar[0], sys->cpu->regs.ar[1]); con_printf(sys->con, "AR 2 = %08X %08X\n", sys->cpu->regs.ar[2], sys->cpu->regs.ar[3]); con_printf(sys->con, "AR 4 = %08X %08X\n", sys->cpu->regs.ar[4], sys->cpu->regs.ar[5]); con_printf(sys->con, "AR 6 = %08X %08X\n", sys->cpu->regs.ar[6], sys->cpu->regs.ar[7]); con_printf(sys->con, "AR 8 = %08X %08X\n", sys->cpu->regs.ar[8], sys->cpu->regs.ar[9]); con_printf(sys->con, "AR 10 = %08X %08X\n", sys->cpu->regs.ar[10], sys->cpu->regs.ar[11]); con_printf(sys->con, "AR 12 = %08X %08X\n", sys->cpu->regs.ar[12], sys->cpu->regs.ar[13]); con_printf(sys->con, "AR 14 = %08X %08X\n", sys->cpu->regs.ar[14], sys->cpu->regs.ar[15]); return 0; } static void __d_psw(struct virt_sys *sys, int zarch, char *name, u64 obase, u64 nbase, u32 *odata, u32 *ndata, int idx) { if (zarch) { con_printf(sys->con, "%s %04X %3lX OLD %08X %08X %08X %08X\n", name, 0xffff, obase+(idx*16), odata[0+(idx*4)], odata[1+(idx*4)], odata[2+(idx*4)], odata[3+(idx*4)]); con_printf(sys->con, " %3lX NEW %08X %08X %08X %08X\n", nbase+(idx*16), ndata[0+(idx*4)], ndata[1+(idx*4)], ndata[2+(idx*4)], ndata[3+(idx*4)]); } else { con_printf(sys->con, "%s %04X %3lX OLD %08X %08X\n", name, 0xffff, obase+(idx*8), odata[0+(idx*2)], odata[1+(idx*2)]); con_printf(sys->con, " %3lX NEW %08X %08X\n", nbase+(idx*8), ndata[0+(idx*2)], ndata[1+(idx*2)]); } } enum { D_PSW_CUR = 0x01, D_PSW_EXT = 0x02, D_PSW_SVC = 0x04, D_PSW_PRG = 0x08, D_PSW_MCH = 0x10, D_PSW_IO = 0x20, D_PSW_RST = 0x40, D_PSW_ALL = 0x7f, }; /* *!!! DISPLAY PSW *!! SYNTAX *! \tok{\sc Display} \tok{\sc PSW} *!! XATNYS *!! AUTH G *!! PURPOSE *! Displays the guest's PSW. *! *! \cbstart *! If the guest is in ESA/390 mode, the 8-byte PSW is displayed. *! *! If the guest is in z/Architecture mode, the 16-byte PSW is displayed. *! \cbend */ static int cmd_display_psw(struct virt_sys *sys, char *cmd, int len) { u32 odata[6*sizeof(struct psw)/sizeof(u32)]; u32 ndata[6*sizeof(struct psw)/sizeof(u32)]; u64 obase, nbase; u64 glen; int oret, nret; int disp = 0; int zarch; SHELL_CMD_AUTH(sys, G); if (!strcasecmp(cmd, "ALL")) disp = D_PSW_ALL; else if (!strcasecmp(cmd, "RST")) disp = D_PSW_RST; else if (!strcasecmp(cmd, "EXT")) disp = D_PSW_EXT; else if (!strcasecmp(cmd, "SVC")) disp = D_PSW_SVC; else if (!strcasecmp(cmd, "PRG")) disp = D_PSW_PRG; else if (!strcasecmp(cmd, "MCH")) disp = D_PSW_MCH; else if (!strcasecmp(cmd, "I/O")) disp = D_PSW_IO; else disp = D_PSW_CUR; zarch = VCPU_ZARCH(sys->cpu); if (disp & D_PSW_CUR) { u32 *ptr = (u32*) &sys->cpu->sie_cb.gpsw; if (zarch) con_printf(sys->con, "PSW = %08X %08X %08X %08X\n", ptr[0], ptr[1], ptr[2], ptr[3]); else con_printf(sys->con, "PSW = %08X %08X\n", ptr[0], ptr[1]); } if (zarch) { obase = 0x120; nbase = 0x1A0; } else { obase = 0x18; nbase = 0x58; } glen = sizeof(struct psw) * 6; oret = memcpy_from_guest(obase, odata, &glen); glen = sizeof(struct psw) * 6; nret = memcpy_from_guest(nbase, ndata, &glen); if (oret || nret) { con_printf(sys->con, "Failed to fetch old/new PSWs from " "guest storage\n"); return oret ? oret : nret; } if (disp & D_PSW_RST) __d_psw(sys, zarch, "RST", obase, nbase, odata, ndata, 0); if (disp & D_PSW_EXT) __d_psw(sys, zarch, "EXT", obase, nbase, odata, ndata, 1); if (disp & D_PSW_SVC) __d_psw(sys, zarch, "SVC", obase, nbase, odata, ndata, 2); if (disp & D_PSW_PRG) __d_psw(sys, zarch, "PRG", obase, nbase, odata, ndata, 3); if (disp & D_PSW_MCH) __d_psw(sys, zarch, "MCH", obase, nbase, odata, ndata, 4); if (disp & D_PSW_IO) __d_psw(sys, zarch, "I/O", obase, nbase, odata, ndata, 5); return 0; } static void __do_display_schib(struct virt_cons *con, struct virt_device *vdev) { con_printf(con, "%05X %04X %08X %d %02X %02X %02X %02X %02X " "---- %02X %02X %02X%02X%02X%02X %02X%02X%02X%02X\n", vdev->sch, vdev->pmcw.dev_num, vdev->pmcw.interrupt_param, vdev->pmcw.isc, ((vdev->pmcw.e << 7) | (vdev->pmcw.lm << 5) | (vdev->pmcw.mm << 3) | (vdev->pmcw.d << 2) | (vdev->pmcw.t << 1) | (vdev->pmcw.v)), vdev->pmcw.lpm, vdev->pmcw.pnom, vdev->pmcw.lpum, vdev->pmcw.pim, /* MBI */ vdev->pmcw.pom, vdev->pmcw.pam, vdev->pmcw.chpid[0], vdev->pmcw.chpid[1], vdev->pmcw.chpid[2], vdev->pmcw.chpid[3], vdev->pmcw.chpid[4], vdev->pmcw.chpid[5], vdev->pmcw.chpid[6], vdev->pmcw.chpid[7]); } /* *!!! DISPLAY SCHIB *!! SYNTAX *! \tok{\sc Display} \tok{\sc SCHIB} *! \begin{stack} \tok{ALL} \\ <schib> \end{stack} *!! XATNYS *!! AUTH G *!! PURPOSE *! Displays the guest's subchannel control block information */ static int cmd_display_schib(struct virt_sys *sys, char *cmd, int len) { struct virt_device *vdev; u64 sch; int all; SHELL_CMD_AUTH(sys, G); if (strcasecmp(cmd, "ALL")) { cmd = __extract_hex(cmd, &sch); if (IS_ERR(cmd)) return PTR_ERR(cmd); /* sch number must be: X'0001____' */ if ((sch & 0xffff0000) != 0x00010000) return -EINVAL; all = 0; } else all = 1; /* find the virtual device */ for_each_vdev(sys, vdev) { if ((vdev->sch == (u32) sch) || all) { if (!all || all == 1) { con_printf(sys->con, "SCHIB DEV INT-PARM ISC FLG LP " "PNO LPU PI MBI PO PA CHPID0-3 CHPID4-7\n"); all = (all ? 2 : 0); } __do_display_schib(sys->con, vdev); if (!all) break; } } return 0; } static struct cpcmd cmd_tbl_display[] = { {"AR", cmd_display_ar, NULL}, {"A", cmd_display_ar, NULL}, {"CR", cmd_display_cr, NULL}, {"C", cmd_display_cr, NULL}, {"FPCR", cmd_display_fpcr, NULL}, {"FPR", cmd_display_fpr, NULL}, {"FP", cmd_display_fpr, NULL}, {"F", cmd_display_fpr, NULL}, {"GPR", cmd_display_gpr, NULL}, {"GP", cmd_display_gpr, NULL}, {"G", cmd_display_gpr, NULL}, {"PSW", cmd_display_psw, NULL}, {"SCHIB", cmd_display_schib, NULL}, {"SIECB", cmd_display_siecb, NULL}, {"STORAGE", cmd_display_storage, NULL}, {"STORAG", cmd_display_storage, NULL}, {"STORA", cmd_display_storage, NULL}, {"STOR", cmd_display_storage, NULL}, {"STO", cmd_display_storage, NULL}, {"", NULL, NULL}, };