crash/ia64.c
Dave Anderson 9531d0f551 For many years, Xen Dom0 dumps could only be saved in ELF format.
Since makedumpfile commit 349a0ed1, it is now possible to save Xen
dumps in compressed kdump format.  This patch set adds support for
these files.  Two new files, xen_dom0.c and xen_dom0.h, have been
added to provide the common functionality required by both ELF and
compressed kdump formats.
(ptesarik@suse.cz)
2015-09-25 09:14:57 -04:00

4450 lines
125 KiB
C

/* ia64.c - core analysis suite
*
* Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
* Copyright (C) 2002-2013 David Anderson
* Copyright (C) 2002-2013 Red Hat, Inc. All rights reserved.
*
* This program 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.
*
* This program 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.
*/
#ifdef IA64
#include "defs.h"
#include "xen_hyper_defs.h"
#include <sys/prctl.h>
static int ia64_verify_symbol(const char *, ulong, char);
static int ia64_eframe_search(struct bt_info *);
static void ia64_back_trace_cmd(struct bt_info *);
static void ia64_old_unwind(struct bt_info *);
static void ia64_old_unwind_init(void);
static void try_old_unwind(struct bt_info *);
static void ia64_dump_irq(int);
static ulong ia64_processor_speed(void);
static int ia64_vtop_4l(ulong, physaddr_t *paddr, ulong *pgd, int, int);
static int ia64_vtop(ulong, physaddr_t *paddr, ulong *pgd, int, int);
static int ia64_uvtop(struct task_context *, ulong, physaddr_t *, int);
static int ia64_kvtop(struct task_context *, ulong, physaddr_t *, int);
static ulong ia64_get_task_pgd(ulong);
static ulong ia64_get_pc(struct bt_info *);
static ulong ia64_get_sp(struct bt_info *);
static ulong ia64_get_thread_ksp(ulong);
static void ia64_get_stack_frame(struct bt_info *, ulong *, ulong *);
static int ia64_translate_pte(ulong, void *, ulonglong);
static ulong ia64_vmalloc_start(void);
static int ia64_is_task_addr(ulong);
static int ia64_dis_filter(ulong, char *, unsigned int);
static void ia64_dump_switch_stack(ulong, ulong);
static void ia64_cmd_mach(void);
static int ia64_get_smp_cpus(void);
static void ia64_display_machine_stats(void);
static void ia64_display_cpu_data(unsigned int);
static void ia64_display_memmap(void);
static void ia64_create_memmap(void);
static ulong check_mem_limit(void);
static int ia64_verify_paddr(uint64_t);
static int ia64_available_memory(struct efi_memory_desc_t *);
static void ia64_post_init(void);
static ulong ia64_in_per_cpu_mca_stack(void);
static struct line_number_hook ia64_line_number_hooks[];
static ulong ia64_get_stackbase(ulong);
static ulong ia64_get_stacktop(ulong);
static void parse_cmdline_args(void);
static void ia64_calc_phys_start(void);
static int ia64_get_kvaddr_ranges(struct vaddr_range *);
struct unw_frame_info;
static void dump_unw_frame_info(struct unw_frame_info *);
static int old_unw_unwind(struct unw_frame_info *);
static void unw_init_from_blocked_task(struct unw_frame_info *, ulong);
static ulong ia64_rse_slot_num(ulong *);
static ulong *ia64_rse_skip_regs(ulong *, long);
static ulong *ia64_rse_rnat_addr(ulong *);
static ulong rse_read_reg(struct unw_frame_info *, int, int *);
static void rse_function_params(struct unw_frame_info *, char *);
static int ia64_vtop_4l_xen_wpt(ulong, physaddr_t *paddr, ulong *pgd, int, int);
static int ia64_vtop_xen_wpt(ulong, physaddr_t *paddr, ulong *pgd, int, int);
static int ia64_xen_kdump_p2m_create(struct xen_kdump_data *);
static int ia64_xendump_p2m_create(struct xendump_data *);
static void ia64_debug_dump_page(FILE *, char *, char *);
static char *ia64_xendump_load_page(ulong, struct xendump_data *);
static int ia64_xendump_page_index(ulong, struct xendump_data *);
static ulong ia64_xendump_panic_task(struct xendump_data *);
static void ia64_get_xendump_regs(struct xendump_data *, struct bt_info *, ulong *, ulong *);
static void ia64_init_hyper(int);
struct machine_specific ia64_machine_specific = { 0 };
void
ia64_init(int when)
{
struct syment *sp, *spn;
if (XEN_HYPER_MODE()) {
ia64_init_hyper(when);
return;
}
switch (when)
{
case SETUP_ENV:
#if defined(PR_SET_FPEMU) && defined(PR_FPEMU_NOPRINT)
prctl(PR_SET_FPEMU, PR_FPEMU_NOPRINT, 0, 0, 0);
#endif
#if defined(PR_SET_UNALIGN) && defined(PR_UNALIGN_NOPRINT)
prctl(PR_SET_UNALIGN, PR_UNALIGN_NOPRINT, 0, 0, 0);
#endif
break;
case PRE_SYMTAB:
machdep->verify_symbol = ia64_verify_symbol;
machdep->machspec = &ia64_machine_specific;
if (pc->flags & KERNEL_DEBUG_QUERY)
return;
machdep->pagesize = memory_page_size();
machdep->pageshift = ffs(machdep->pagesize) - 1;
machdep->pageoffset = machdep->pagesize - 1;
machdep->pagemask = ~(machdep->pageoffset);
switch (machdep->pagesize)
{
case 4096:
machdep->stacksize = (power(2, 3) * PAGESIZE());
break;
case 8192:
machdep->stacksize = (power(2, 2) * PAGESIZE());
break;
case 16384:
machdep->stacksize = (power(2, 1) * PAGESIZE());
break;
case 65536:
machdep->stacksize = (power(2, 0) * PAGESIZE());
break;
default:
machdep->stacksize = 32*1024;
break;
}
if ((machdep->pgd = (char *)malloc(PAGESIZE())) == NULL)
error(FATAL, "cannot malloc pgd space.");
if ((machdep->pud = (char *)malloc(PAGESIZE())) == NULL)
error(FATAL, "cannot malloc pud space.");
if ((machdep->pmd = (char *)malloc(PAGESIZE())) == NULL)
error(FATAL, "cannot malloc pmd space.");
if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL)
error(FATAL, "cannot malloc ptbl space.");
machdep->last_pgd_read = 0;
machdep->last_pud_read = 0;
machdep->last_pmd_read = 0;
machdep->last_ptbl_read = 0;
machdep->verify_paddr = ia64_verify_paddr;
machdep->get_kvaddr_ranges = ia64_get_kvaddr_ranges;
machdep->ptrs_per_pgd = PTRS_PER_PGD;
machdep->machspec->phys_start = UNKNOWN_PHYS_START;
if (machdep->cmdline_args[0])
parse_cmdline_args();
if (ACTIVE())
machdep->flags |= DEVMEMRD;
break;
case PRE_GDB:
if (pc->flags & KERNEL_DEBUG_QUERY)
return;
/*
* Until the kernel core dump and va_server library code
* do the right thing with respect to the configured page size,
* try to recognize a fatal inequity between the compiled-in
* page size and the page size used by the kernel.
*/
if ((sp = symbol_search("empty_zero_page")) &&
(spn = next_symbol(NULL, sp)) &&
((spn->value - sp->value) != PAGESIZE()))
error(FATAL,
"compiled-in page size: %d (apparent) kernel page size: %ld\n",
PAGESIZE(), spn->value - sp->value);
machdep->kvbase = KERNEL_VMALLOC_BASE;
machdep->identity_map_base = KERNEL_CACHED_BASE;
machdep->is_kvaddr = generic_is_kvaddr;
machdep->is_uvaddr = generic_is_uvaddr;
machdep->eframe_search = ia64_eframe_search;
machdep->back_trace = ia64_back_trace_cmd;
machdep->processor_speed = ia64_processor_speed;
machdep->uvtop = ia64_uvtop;
machdep->kvtop = ia64_kvtop;
machdep->get_task_pgd = ia64_get_task_pgd;
machdep->dump_irq = ia64_dump_irq;
machdep->get_stack_frame = ia64_get_stack_frame;
machdep->get_stackbase = ia64_get_stackbase;
machdep->get_stacktop = ia64_get_stacktop;
machdep->translate_pte = ia64_translate_pte;
machdep->memory_size = generic_memory_size;
machdep->vmalloc_start = ia64_vmalloc_start;
machdep->is_task_addr = ia64_is_task_addr;
machdep->dis_filter = ia64_dis_filter;
machdep->cmd_mach = ia64_cmd_mach;
machdep->get_smp_cpus = ia64_get_smp_cpus;
machdep->line_number_hooks = ia64_line_number_hooks;
machdep->value_to_symbol = generic_machdep_value_to_symbol;
machdep->init_kernel_pgd = NULL;
machdep->get_irq_affinity = generic_get_irq_affinity;
machdep->show_interrupts = generic_show_interrupts;
if ((sp = symbol_search("_stext"))) {
machdep->machspec->kernel_region =
VADDR_REGION(sp->value);
machdep->machspec->kernel_start = sp->value;
} else {
machdep->machspec->kernel_region = KERNEL_CACHED_REGION;
machdep->machspec->kernel_start = KERNEL_CACHED_BASE;
}
if (machdep->machspec->kernel_region == KERNEL_VMALLOC_REGION) {
machdep->machspec->vmalloc_start =
machdep->machspec->kernel_start +
GIGABYTES((ulong)(4));
if (machdep->machspec->phys_start == UNKNOWN_PHYS_START)
ia64_calc_phys_start();
} else
machdep->machspec->vmalloc_start = KERNEL_VMALLOC_BASE;
machdep->xen_kdump_p2m_create = ia64_xen_kdump_p2m_create;
machdep->xendump_p2m_create = ia64_xendump_p2m_create;
machdep->xendump_panic_task = ia64_xendump_panic_task;
machdep->get_xendump_regs = ia64_get_xendump_regs;
break;
case POST_GDB:
STRUCT_SIZE_INIT(cpuinfo_ia64, "cpuinfo_ia64");
STRUCT_SIZE_INIT(switch_stack, "switch_stack");
MEMBER_OFFSET_INIT(thread_struct_fph, "thread_struct", "fph");
MEMBER_OFFSET_INIT(switch_stack_b0, "switch_stack", "b0");
MEMBER_OFFSET_INIT(switch_stack_ar_bspstore,
"switch_stack", "ar_bspstore");
MEMBER_OFFSET_INIT(switch_stack_ar_pfs,
"switch_stack", "ar_pfs");
MEMBER_OFFSET_INIT(switch_stack_ar_rnat,
"switch_stack", "ar_rnat");
MEMBER_OFFSET_INIT(switch_stack_pr,
"switch_stack", "pr");
MEMBER_OFFSET_INIT(cpuinfo_ia64_proc_freq,
"cpuinfo_ia64", "proc_freq");
MEMBER_OFFSET_INIT(cpuinfo_ia64_unimpl_va_mask,
"cpuinfo_ia64", "unimpl_va_mask");
MEMBER_OFFSET_INIT(cpuinfo_ia64_unimpl_pa_mask,
"cpuinfo_ia64", "unimpl_pa_mask");
if (kernel_symbol_exists("nr_irqs"))
get_symbol_data("nr_irqs", sizeof(unsigned int),
&machdep->nr_irqs);
else if (symbol_exists("irq_desc"))
ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc,
"irq_desc", NULL, 0);
else if (symbol_exists("_irq_desc"))
ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc,
"_irq_desc", NULL, 0);
if (!machdep->hz)
machdep->hz = 1024;
machdep->section_size_bits = _SECTION_SIZE_BITS;
machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
ia64_create_memmap();
break;
case POST_INIT:
ia64_post_init();
break;
case LOG_ONLY:
machdep->machspec = &ia64_machine_specific;
machdep->machspec->kernel_start = kt->vmcoreinfo._stext_SYMBOL;
machdep->machspec->kernel_region =
VADDR_REGION(kt->vmcoreinfo._stext_SYMBOL);
if (machdep->machspec->kernel_region == KERNEL_VMALLOC_REGION) {
machdep->machspec->vmalloc_start =
machdep->machspec->kernel_start +
GIGABYTES((ulong)(4));
ia64_calc_phys_start();
}
break;
}
}
/*
* --machdep <addr> defaults to the physical start location.
*
* Otherwise, it's got to be a "item=value" string, separated
* by commas if more than one is passed in.
*/
void
parse_cmdline_args(void)
{
int index, i, c, errflag;
char *p;
char buf[BUFSIZE];
char *arglist[MAXARGS];
ulong value;
struct machine_specific *ms;
int vm_flag;
ms = &ia64_machine_specific;
vm_flag = 0;
for (index = 0; index < MAX_MACHDEP_ARGS; index++) {
if (!machdep->cmdline_args[index])
break;
if (!strstr(machdep->cmdline_args[index], "=")) {
errflag = 0;
value = htol(machdep->cmdline_args[index],
RETURN_ON_ERROR|QUIET, &errflag);
if (!errflag) {
ms->phys_start = value;
error(NOTE, "setting phys_start to: 0x%lx\n",
ms->phys_start);
} else
error(WARNING, "ignoring --machdep option: %s\n\n",
machdep->cmdline_args[index]);
continue;
}
strcpy(buf, machdep->cmdline_args[index]);
for (p = buf; *p; p++) {
if (*p == ',')
*p = ' ';
}
c = parse_line(buf, arglist);
for (i = 0; i < c; i++) {
errflag = 0;
if (STRNEQ(arglist[i], "phys_start=")) {
p = arglist[i] + strlen("phys_start=");
if (strlen(p)) {
value = htol(p, RETURN_ON_ERROR|QUIET,
&errflag);
if (!errflag) {
ms->phys_start = value;
error(NOTE,
"setting phys_start to: 0x%lx\n",
ms->phys_start);
continue;
}
}
} else if (STRNEQ(arglist[i], "init_stack_size=")) {
p = arglist[i] + strlen("init_stack_size=");
if (strlen(p)) {
value = stol(p, RETURN_ON_ERROR|QUIET,
&errflag);
if (!errflag) {
ms->ia64_init_stack_size = (int)value;
error(NOTE,
"setting init_stack_size to: 0x%x (%d)\n",
ms->ia64_init_stack_size,
ms->ia64_init_stack_size);
continue;
}
}
} else if (STRNEQ(arglist[i], "vm=")) {
vm_flag++;
p = arglist[i] + strlen("vm=");
if (strlen(p)) {
if (STREQ(p, "4l")) {
machdep->flags |= VM_4_LEVEL;
continue;
}
}
}
error(WARNING, "ignoring --machdep option: %s\n", arglist[i]);
}
if (vm_flag) {
switch (machdep->flags & (VM_4_LEVEL))
{
case VM_4_LEVEL:
error(NOTE, "using 4-level pagetable\n");
c++;
break;
default:
error(WARNING, "invalid vm= option\n");
c++;
machdep->flags &= ~(VM_4_LEVEL);
break;
}
}
if (c)
fprintf(fp, "\n");
}
}
int
ia64_in_init_stack(ulong addr)
{
ulong init_stack_addr;
if (!symbol_exists("ia64_init_stack"))
return FALSE;
/*
* ia64_init_stack could be aliased to region 5
*/
init_stack_addr = ia64_VTOP(symbol_value("ia64_init_stack"));
addr = ia64_VTOP(addr);
if ((addr < init_stack_addr) ||
(addr >= (init_stack_addr+machdep->machspec->ia64_init_stack_size)))
return FALSE;
return TRUE;
}
static ulong
ia64_in_per_cpu_mca_stack(void)
{
int plen, i;
ulong flag;
ulong vaddr, paddr, stackbase, stacktop;
ulong *__per_cpu_mca;
struct task_context *tc;
tc = CURRENT_CONTEXT();
if (STRNEQ(CURRENT_COMM(), "INIT"))
flag = INIT;
else if (STRNEQ(CURRENT_COMM(), "MCA"))
flag = MCA;
else
return 0;
if (!symbol_exists("__per_cpu_mca") ||
!(plen = get_array_length("__per_cpu_mca", NULL, 0)) ||
(plen < kt->cpus))
return 0;
vaddr = SWITCH_STACK_ADDR(CURRENT_TASK());
if (VADDR_REGION(vaddr) != KERNEL_CACHED_REGION)
return 0;
paddr = ia64_VTOP(vaddr);
__per_cpu_mca = (ulong *)GETBUF(sizeof(ulong) * kt->cpus);
if (!readmem(symbol_value("__per_cpu_mca"), KVADDR, __per_cpu_mca,
sizeof(ulong) * kt->cpus, "__per_cpu_mca", RETURN_ON_ERROR|QUIET))
return 0;
if (CRASHDEBUG(1)) {
for (i = 0; i < kt->cpus; i++) {
fprintf(fp, "__per_cpu_mca[%d]: %lx\n",
i, __per_cpu_mca[i]);
}
}
stackbase = __per_cpu_mca[tc->processor];
stacktop = stackbase + (STACKSIZE() * 2);
FREEBUF(__per_cpu_mca);
if ((paddr >= stackbase) && (paddr < stacktop))
return flag;
else
return 0;
}
void
ia64_dump_machdep_table(ulong arg)
{
int i, others, verbose;
struct machine_specific *ms;
verbose = FALSE;
ms = &ia64_machine_specific;
if (arg) {
switch (arg)
{
default:
case 1:
verbose = TRUE;
break;
case 2:
if (machdep->flags & NEW_UNWIND) {
machdep->flags &=
~(NEW_UNWIND|NEW_UNW_V1|NEW_UNW_V2|NEW_UNW_V3);
machdep->flags |= OLD_UNWIND;
ms->unwind_init = ia64_old_unwind_init;
ms->unwind = ia64_old_unwind;
ms->dump_unwind_stats = NULL;
ms->unwind_debug = NULL;
} else {
machdep->flags &= ~OLD_UNWIND;
machdep->flags |= NEW_UNWIND;
if (MEMBER_EXISTS("unw_frame_info", "pt")) {
if (MEMBER_EXISTS("pt_regs", "ar_csd")) {
machdep->flags |= NEW_UNW_V3;
ms->unwind_init = unwind_init_v3;
ms->unwind = unwind_v3;
ms->unwind_debug = unwind_debug_v3;
ms->dump_unwind_stats =
dump_unwind_stats_v3;
} else {
machdep->flags |= NEW_UNW_V2;
ms->unwind_init = unwind_init_v2;
ms->unwind = unwind_v2;
ms->unwind_debug = unwind_debug_v2;
ms->dump_unwind_stats =
dump_unwind_stats_v2;
}
} else {
machdep->flags |= NEW_UNW_V1;
ms->unwind_init = unwind_init_v1;
ms->unwind = unwind_v1;
ms->unwind_debug = unwind_debug_v1;
ms->dump_unwind_stats =
dump_unwind_stats_v1;
}
}
ms->unwind_init();
return;
case 3:
if (machdep->flags & NEW_UNWIND)
ms->unwind_debug(arg);
return;
}
}
others = 0;
fprintf(fp, " flags: %lx (", machdep->flags);
/* future flags tests here */
if (machdep->flags & NEW_UNWIND)
fprintf(fp, "%sNEW_UNWIND", others++ ? "|" : "");
if (machdep->flags & NEW_UNW_V1)
fprintf(fp, "%sNEW_UNW_V1", others++ ? "|" : "");
if (machdep->flags & NEW_UNW_V2)
fprintf(fp, "%sNEW_UNW_V2", others++ ? "|" : "");
if (machdep->flags & NEW_UNW_V3)
fprintf(fp, "%sNEW_UNW_V3", others++ ? "|" : "");
if (machdep->flags & OLD_UNWIND)
fprintf(fp, "%sOLD_UNWIND", others++ ? "|" : "");
if (machdep->flags & UNW_OUT_OF_SYNC)
fprintf(fp, "%sUNW_OUT_OF_SYNC", others++ ? "|" : "");
if (machdep->flags & UNW_READ)
fprintf(fp, "%sUNW_READ", others++ ? "|" : "");
if (machdep->flags & UNW_PTREGS)
fprintf(fp, "%sUNW_PTREGS", others++ ? "|" : "");
if (machdep->flags & UNW_R0)
fprintf(fp, "%sUNW_R0", others++ ? "|" : "");
if (machdep->flags & MEM_LIMIT)
fprintf(fp, "%sMEM_LIMIT", others++ ? "|" : "");
if (machdep->flags & DEVMEMRD)
fprintf(fp, "%sDEVMEMRD", others++ ? "|" : "");
if (machdep->flags & INIT)
fprintf(fp, "%sINIT", others++ ? "|" : "");
if (machdep->flags & MCA)
fprintf(fp, "%sMCA", others++ ? "|" : "");
if (machdep->flags & VM_4_LEVEL)
fprintf(fp, "%sVM_4_LEVEL", others++ ? "|" : "");
fprintf(fp, ")\n");
fprintf(fp, " kvbase: %lx\n", machdep->kvbase);
fprintf(fp, " identity_map_base: %lx\n", machdep->identity_map_base);
fprintf(fp, " pagesize: %d\n", machdep->pagesize);
fprintf(fp, " pageshift: %d\n", machdep->pageshift);
fprintf(fp, " pagemask: %llx\n", machdep->pagemask);
fprintf(fp, " pageoffset: %lx\n", machdep->pageoffset);
fprintf(fp, " stacksize: %ld\n", machdep->stacksize);
fprintf(fp, " hz: %d\n", machdep->hz);
fprintf(fp, " mhz: %d\n", machdep->hz);
fprintf(fp, " memsize: %ld (0x%lx)\n",
machdep->memsize, machdep->memsize);
fprintf(fp, " bits: %d\n", machdep->bits);
fprintf(fp, " nr_irqs: %d\n", machdep->nr_irqs);
fprintf(fp, " eframe_search: ia64_eframe_search()\n");
fprintf(fp, " back_trace: ia64_back_trace_cmd()\n");
fprintf(fp, "get_processor_speed: ia64_processor_speed()\n");
fprintf(fp, " uvtop: ia64_uvtop()\n");
fprintf(fp, " kvtop: ia64_kvtop()\n");
fprintf(fp, " get_task_pgd: ia64_get_task_pgd()\n");
fprintf(fp, " dump_irq: ia64_dump_irq()\n");
fprintf(fp, " get_stack_frame: ia64_get_stack_frame()\n");
fprintf(fp, " get_stackbase: ia64_get_stackbase()\n");
fprintf(fp, " get_stacktop: ia64_get_stacktop()\n");
fprintf(fp, " translate_pte: ia64_translate_pte()\n");
fprintf(fp, " memory_size: generic_memory_size()\n");
fprintf(fp, " vmalloc_start: ia64_vmalloc_start()\n");
fprintf(fp, " is_task_addr: ia64_is_task_addr()\n");
fprintf(fp, " verify_symbol: ia64_verify_symbol()\n");
fprintf(fp, " dis_filter: ia64_dis_filter()\n");
fprintf(fp, " cmd_mach: ia64_cmd_mach()\n");
fprintf(fp, " get_smp_cpus: ia64_get_smp_cpus()\n");
fprintf(fp, " get_kvaddr_ranges: ia64_get_kvaddr_ranges()\n");
fprintf(fp, " is_kvaddr: generic_is_kvaddr()\n");
fprintf(fp, " is_uvaddr: generic_is_uvaddr()\n");
fprintf(fp, " verify_paddr: %s()\n",
(machdep->verify_paddr == ia64_verify_paddr) ?
"ia64_verify_paddr" : "generic_verify_paddr");
fprintf(fp, " get_irq_affinity: generic_get_irq_affinity()\n");
fprintf(fp, " show_interrupts: generic_show_interrupts()\n");
fprintf(fp, " init_kernel_pgd: NULL\n");
fprintf(fp, "xen_kdump_p2m_create: ia64_xen_kdump_p2m_create()\n");
fprintf(fp, " xendump_p2m_create: ia64_xendump_p2m_create()\n");
fprintf(fp, " xendump_panic_task: ia64_xendump_panic_task()\n");
fprintf(fp, " get_xendump_regs: ia64_get_xendump_regs()\n");
fprintf(fp, " value_to_symbol: generic_machdep_value_to_symbol()\n");
fprintf(fp, " line_number_hooks: ia64_line_number_hooks\n");
fprintf(fp, " last_pgd_read: %lx\n", machdep->last_pgd_read);
fprintf(fp, " last_pud_read: %lx\n", machdep->last_pud_read);
fprintf(fp, " last_pmd_read: %lx\n", machdep->last_pmd_read);
fprintf(fp, " last_ptbl_read: %lx\n", machdep->last_ptbl_read);
fprintf(fp, " pgd: %lx\n", (ulong)machdep->pgd);
fprintf(fp, " pud: %lx\n", (ulong)machdep->pud);
fprintf(fp, " pmd: %lx\n", (ulong)machdep->pmd);
fprintf(fp, " ptbl: %lx\n", (ulong)machdep->ptbl);
fprintf(fp, " ptrs_per_pgd: %d\n", machdep->ptrs_per_pgd);
for (i = 0; i < MAX_MACHDEP_ARGS; i++) {
fprintf(fp, " cmdline_args[%d]: %s\n",
i, machdep->cmdline_args[i] ?
machdep->cmdline_args[i] : "(unused)");
}
fprintf(fp, " section_size_bits: %ld\n", machdep->section_size_bits);
fprintf(fp, " max_physmem_bits: %ld\n", machdep->max_physmem_bits);
fprintf(fp, " sections_per_root: %ld\n", machdep->sections_per_root);
fprintf(fp, " machspec: ia64_machine_specific\n");
fprintf(fp, " cpu_data_address: %lx\n",
machdep->machspec->cpu_data_address);
fprintf(fp, " unimpl_va_mask: %lx\n",
machdep->machspec->unimpl_va_mask);
fprintf(fp, " unimpl_pa_mask: %lx\n",
machdep->machspec->unimpl_pa_mask);
fprintf(fp, " unw: %lx\n",
(ulong)machdep->machspec->unw);
fprintf(fp, " unw_tables_offset: %ld\n",
machdep->machspec->unw_tables_offset);
fprintf(fp, " unw_kernel_table_offset: %ld %s\n",
machdep->machspec->unw_kernel_table_offset,
machdep->machspec->unw_kernel_table_offset ? "" : "(unused)");
fprintf(fp, " unw_pt_regs_offsets: %ld %s\n",
machdep->machspec->unw_pt_regs_offsets,
machdep->machspec->unw_pt_regs_offsets ? "" : "(unused)");
fprintf(fp, " script_index: %d\n",
machdep->machspec->script_index);
fprintf(fp, " script_cache: %lx%s",
(ulong)machdep->machspec->script_cache,
machdep->flags & OLD_UNWIND ? "\n" : " ");
if (machdep->flags & NEW_UNWIND)
ms->dump_unwind_stats();
if (!(machdep->flags & (NEW_UNWIND|OLD_UNWIND)))
fprintf(fp, "\n");
fprintf(fp, " mem_limit: %lx\n",
machdep->machspec->mem_limit);
fprintf(fp, " kernel_region: %ld\n",
machdep->machspec->kernel_region);
fprintf(fp, " kernel_start: %lx\n",
machdep->machspec->kernel_start);
fprintf(fp, " phys_start: %lx (%lx)\n",
machdep->machspec->phys_start,
machdep->machspec->phys_start & KERNEL_TR_PAGE_MASK);
fprintf(fp, " vmalloc_start: %lx\n",
machdep->machspec->vmalloc_start);
fprintf(fp, " ia64_memmap: %lx\n",
(ulong)machdep->machspec->ia64_memmap);
fprintf(fp, " efi_memmap_size: %ld\n",
(ulong)machdep->machspec->efi_memmap_size);
fprintf(fp, " efi_memdesc_size: %ld\n",
(ulong)machdep->machspec->efi_memdesc_size);
fprintf(fp, " unwind_init: ");
if (ms->unwind_init == unwind_init_v1)
fprintf(fp, "unwind_init_v1()\n");
else if (ms->unwind_init == unwind_init_v2)
fprintf(fp, "unwind_init_v2()\n");
else if (ms->unwind_init == unwind_init_v3)
fprintf(fp, "unwind_init_v3()\n");
else if (ms->unwind_init == ia64_old_unwind_init)
fprintf(fp, "ia64_old_unwind_init()\n");
else
fprintf(fp, "%lx\n", (ulong)ms->unwind_init);
fprintf(fp, " unwind: ");
if (ms->unwind == unwind_v1)
fprintf(fp, "unwind_v1()\n");
else if (ms->unwind == unwind_v2)
fprintf(fp, "unwind_v2()\n");
else if (ms->unwind == unwind_v3)
fprintf(fp, "unwind_v3()\n");
else if (ms->unwind == ia64_old_unwind)
fprintf(fp, "ia64_old_unwind()\n");
else
fprintf(fp, "%lx\n", (ulong)ms->unwind);
fprintf(fp, " dump_unwind_stats: ");
if (ms->dump_unwind_stats == dump_unwind_stats_v1)
fprintf(fp, "dump_unwind_stats_v1()\n");
else if (ms->dump_unwind_stats == dump_unwind_stats_v2)
fprintf(fp, "dump_unwind_stats_v2()\n");
else if (ms->dump_unwind_stats == dump_unwind_stats_v3)
fprintf(fp, "dump_unwind_stats_v3()\n");
else
fprintf(fp, "%lx\n", (ulong)ms->dump_unwind_stats);
fprintf(fp, " unwind_debug: ");
if (ms->unwind_debug == unwind_debug_v1)
fprintf(fp, "unwind_debug_v1()\n");
else if (ms->unwind_debug == unwind_debug_v2)
fprintf(fp, "unwind_debug_v2()\n");
else if (ms->unwind_debug == unwind_debug_v3)
fprintf(fp, "unwind_debug_v3()\n");
else
fprintf(fp, "%lx\n", (ulong)ms->unwind_debug);
fprintf(fp, " ia64_init_stack_size: %d\n",
ms->ia64_init_stack_size);
if (verbose)
ia64_display_memmap();
}
/*
* Keep or reject a symbol from the namelist.
*/
static int
ia64_verify_symbol(const char *name, ulong value, char type)
{
ulong region;
if (!name || !strlen(name))
return FALSE;
if (XEN_HYPER_MODE() && STREQ(name, "__per_cpu_shift"))
return TRUE;
if (CRASHDEBUG(8))
fprintf(fp, "%016lx %s\n", value, name);
// if (STREQ(name, "phys_start") && type == 'A')
// if (machdep->machspec->phys_start == UNKNOWN_PHYS_START)
// machdep->machspec->phys_start = value;
region = VADDR_REGION(value);
return (((region == KERNEL_CACHED_REGION) ||
(region == KERNEL_VMALLOC_REGION)));
}
/*
* Look for likely exception frames in a stack.
*/
static int
ia64_eframe_search(struct bt_info *bt)
{
return(error(FATAL,
"ia64_eframe_search: not available for this architecture\n"));
}
/*
* Unroll a kernel stack.
*/
#define BT_SWITCH_STACK BT_SYMBOLIC_ARGS
static void
ia64_back_trace_cmd(struct bt_info *bt)
{
struct machine_specific *ms = &ia64_machine_specific;
if (bt->flags & BT_SWITCH_STACK)
ia64_dump_switch_stack(bt->task, 0);
if (machdep->flags & UNW_OUT_OF_SYNC)
error(FATAL,
"kernel and %s unwind data structures are out of sync\n",
pc->program_name);
ms->unwind(bt);
if (bt->flags & BT_UNWIND_ERROR)
try_old_unwind(bt);
}
/*
* Dump the IRQ table.
*/
static void
ia64_dump_irq(int irq)
{
if (symbol_exists("irq_desc") || symbol_exists("_irq_desc") ||
kernel_symbol_exists("irq_desc_ptrs")) {
machdep->dump_irq = generic_dump_irq;
return(generic_dump_irq(irq));
}
error(FATAL,
"ia64_dump_irq: neither irq_desc or _irq_desc exist\n");
}
/*
* Calculate and return the speed of the processor.
*/
static ulong
ia64_processor_speed(void)
{
ulong mhz, proc_freq;
int bootstrap_processor;
if (machdep->mhz)
return(machdep->mhz);
mhz = 0;
bootstrap_processor = 0;
if (!machdep->machspec->cpu_data_address ||
!VALID_STRUCT(cpuinfo_ia64) ||
!VALID_MEMBER(cpuinfo_ia64_proc_freq))
return (machdep->mhz = mhz);
if (symbol_exists("bootstrap_processor"))
get_symbol_data("bootstrap_processor", sizeof(int),
&bootstrap_processor);
if (bootstrap_processor == -1)
bootstrap_processor = 0;
readmem(machdep->machspec->cpu_data_address +
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);
}
/* Generic abstraction to translate user or kernel virtual
* addresses to physical using a 4 level page table.
*/
static int
ia64_vtop_4l(ulong vaddr, physaddr_t *paddr, ulong *pgd, int verbose, int usr)
{
ulong *page_dir;
ulong *page_upper;
ulong *page_middle;
ulong *page_table;
ulong pgd_pte;
ulong pud_pte;
ulong pmd_pte;
ulong pte;
ulong region, offset;
if (usr) {
region = VADDR_REGION(vaddr);
offset = (vaddr >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1);
offset |= (region << (PAGESHIFT() - 6));
page_dir = pgd + offset;
} else {
if (!(pgd = (ulong *)vt->kernel_pgd[0]))
error(FATAL, "cannot determine kernel pgd pointer\n");
page_dir = pgd + ((vaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1));
}
if (verbose)
fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));
if (verbose)
fprintf(fp, " PGD: %lx => %lx\n", (ulong)page_dir, pgd_pte);
if (!(pgd_pte))
return FALSE;
offset = (vaddr >> PUD_SHIFT) & (PTRS_PER_PUD - 1);
page_upper = (ulong *)(PTOV(pgd_pte & _PFN_MASK)) + offset;
FILL_PUD(PAGEBASE(page_upper), KVADDR, PAGESIZE());
pud_pte = ULONG(machdep->pud + PAGEOFFSET(page_upper));
if (verbose)
fprintf(fp, " PUD: %lx => %lx\n", (ulong)page_upper, pud_pte);
if (!(pud_pte))
return FALSE;
offset = (vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
page_middle = (ulong *)(PTOV(pud_pte & _PFN_MASK)) + offset;
FILL_PMD(PAGEBASE(page_middle), KVADDR, PAGESIZE());
pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));
if (verbose)
fprintf(fp, " PMD: %lx => %lx\n", (ulong)page_middle, pmd_pte);
if (!(pmd_pte))
return FALSE;
offset = (vaddr >> PAGESHIFT()) & (PTRS_PER_PTE - 1);
page_table = (ulong *)(PTOV(pmd_pte & _PFN_MASK)) + offset;
FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE());
pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
if (verbose)
fprintf(fp, " PTE: %lx => %lx\n", (ulong)page_table, pte);
if (!(pte & (_PAGE_P | _PAGE_PROTNONE))) {
if (usr)
*paddr = pte;
if (pte && verbose) {
fprintf(fp, "\n");
ia64_translate_pte(pte, 0, 0);
}
return FALSE;
}
*paddr = (pte & _PFN_MASK) + PAGEOFFSET(vaddr);
if (verbose) {
fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr));
ia64_translate_pte(pte, 0, 0);
}
return TRUE;
}
/* Generic abstraction to translate user or kernel virtual
* addresses to physical using a 3 level page table.
*/
static int
ia64_vtop(ulong vaddr, physaddr_t *paddr, ulong *pgd, int verbose, int usr)
{
ulong *page_dir;
ulong *page_middle;
ulong *page_table;
ulong pgd_pte;
ulong pmd_pte;
ulong pte;
ulong region, offset;
if (usr) {
region = VADDR_REGION(vaddr);
offset = (vaddr >> PGDIR_SHIFT_3L) & ((PTRS_PER_PGD >> 3) - 1);
offset |= (region << (PAGESHIFT() - 6));
page_dir = pgd + offset;
} else {
if (!(pgd = (ulong *)vt->kernel_pgd[0]))
error(FATAL, "cannot determine kernel pgd pointer\n");
page_dir = pgd + ((vaddr >> PGDIR_SHIFT_3L) & (PTRS_PER_PGD - 1));
}
if (verbose)
fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));
if (verbose)
fprintf(fp, " PGD: %lx => %lx\n", (ulong)page_dir, pgd_pte);
if (!(pgd_pte))
return FALSE;
offset = (vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
page_middle = (ulong *)(PTOV(pgd_pte & _PFN_MASK)) + offset;
FILL_PMD(PAGEBASE(page_middle), KVADDR, PAGESIZE());
pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));
if (verbose)
fprintf(fp, " PMD: %lx => %lx\n", (ulong)page_middle, pmd_pte);
if (!(pmd_pte))
return FALSE;
offset = (vaddr >> PAGESHIFT()) & (PTRS_PER_PTE - 1);
page_table = (ulong *)(PTOV(pmd_pte & _PFN_MASK)) + offset;
FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE());
pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
if (verbose)
fprintf(fp, " PTE: %lx => %lx\n", (ulong)page_table, pte);
if (!(pte & (_PAGE_P | _PAGE_PROTNONE))) {
if (usr)
*paddr = pte;
if (pte && verbose) {
fprintf(fp, "\n");
ia64_translate_pte(pte, 0, 0);
}
return FALSE;
}
*paddr = (pte & _PFN_MASK) + PAGEOFFSET(vaddr);
if (verbose) {
fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr));
ia64_translate_pte(pte, 0, 0);
}
return TRUE;
}
/*
* Translates a user virtual address to its physical address. cmd_vtop()
* sets the verbose flag so that the pte translation gets displayed; all
* other callers quietly accept the translation.
*
* This routine can also take mapped kernel virtual addresses if the -u flag
* was passed to cmd_vtop(). If so, it makes the translation using the
* swapper_pg_dir, making it irrelevant in this processor's case.
*/
static int
ia64_uvtop(struct task_context *tc, ulong uvaddr, physaddr_t *paddr, int verbose)
{
ulong mm;
ulong *pgd;
if (!tc)
error(FATAL, "current context invalid\n");
*paddr = 0;
if (IS_KVADDR(uvaddr))
return ia64_kvtop(tc, uvaddr, paddr, verbose);
if ((mm = task_mm(tc->task, TRUE)))
pgd = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd));
else
readmem(tc->mm_struct + OFFSET(mm_struct_pgd), KVADDR, &pgd,
sizeof(long), "mm_struct pgd", FAULT_ON_ERROR);
if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES)) {
if (machdep->flags & VM_4_LEVEL)
return ia64_vtop_4l_xen_wpt(uvaddr, paddr, pgd, verbose, 1);
else
return ia64_vtop_xen_wpt(uvaddr, paddr, pgd, verbose, 1);
} else {
if (machdep->flags & VM_4_LEVEL)
return ia64_vtop_4l(uvaddr, paddr, pgd, verbose, 1);
else
return ia64_vtop(uvaddr, paddr, pgd, verbose, 1);
}
}
/*
* Translates a kernel virtual address to its physical address. cmd_vtop()
* sets the verbose flag so that the pte translation gets displayed; all
* other callers quietly accept the translation.
*/
static int
ia64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose)
{
ulong *pgd;
if (!IS_KVADDR(kvaddr))
return FALSE;
if (!vt->vmalloc_start) {
*paddr = ia64_VTOP(kvaddr);
return TRUE;
}
switch (VADDR_REGION(kvaddr))
{
case KERNEL_UNCACHED_REGION:
*paddr = kvaddr - KERNEL_UNCACHED_BASE;
if (verbose)
fprintf(fp, "[UNCACHED MEMORY]\n");
return TRUE;
case KERNEL_CACHED_REGION:
*paddr = ia64_VTOP(kvaddr);
if (verbose)
fprintf(fp, "[MAPPED IN TRANSLATION REGISTER]\n");
return TRUE;
case KERNEL_VMALLOC_REGION:
if (ia64_IS_VMALLOC_ADDR(kvaddr))
break;
if ((kvaddr < machdep->machspec->kernel_start) &&
(machdep->machspec->kernel_region ==
KERNEL_VMALLOC_REGION)) {
*paddr = PADDR_NOT_AVAILABLE;
return FALSE;
}
*paddr = ia64_VTOP(kvaddr);
if (verbose)
fprintf(fp, "[MAPPED IN TRANSLATION REGISTER]\n");
return TRUE;
}
if (!(pgd = (ulong *)vt->kernel_pgd[0]))
error(FATAL, "cannot determine kernel pgd pointer\n");
if (XEN() && (kt->xen_flags & WRITABLE_PAGE_TABLES)) {
if (machdep->flags & VM_4_LEVEL)
return ia64_vtop_4l_xen_wpt(kvaddr, paddr, pgd, verbose, 0);
else
return ia64_vtop_xen_wpt(kvaddr, paddr, pgd, verbose, 0);
} else {
if (machdep->flags & VM_4_LEVEL)
return ia64_vtop_4l(kvaddr, paddr, pgd, verbose, 0);
else
return ia64_vtop(kvaddr, paddr, pgd, verbose, 0);
}
}
/*
* Even though thread_info structs are used in 2.6, they
* are not the stack base. (until further notice...)
*/
static ulong
ia64_get_stackbase(ulong task)
{
return (task);
}
static ulong
ia64_get_stacktop(ulong task)
{
return (ia64_get_stackbase(task) + STACKSIZE());
}
/*
* Get the relevant page directory pointer from a task structure.
*/
static ulong
ia64_get_task_pgd(ulong task)
{
return (error(FATAL, "ia64_get_task_pgd: N/A\n"));
}
static void
ia64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
{
if (pcp)
*pcp = ia64_get_pc(bt);
if (spp)
*spp = ia64_get_sp(bt);
}
/*
* Return the kernel switch_stack b0 value.
*/
static ulong
ia64_get_pc(struct bt_info *bt)
{
ulong b0;
readmem(SWITCH_STACK_ADDR(bt->task) + OFFSET(switch_stack_b0), KVADDR,
&b0, sizeof(void *), "switch_stack b0", FAULT_ON_ERROR);
return b0;
}
/*
* Return the kernel switch_stack ar_bspstore value.
* If it's "bt -t" request, calculate the register backing store offset.
*/
static ulong
ia64_get_sp(struct bt_info *bt)
{
ulong bspstore;
readmem(SWITCH_STACK_ADDR(bt->task) + OFFSET(switch_stack_ar_bspstore),
KVADDR, &bspstore, sizeof(void *), "switch_stack ar_bspstore",
FAULT_ON_ERROR);
if (bt->flags &
(BT_TEXT_SYMBOLS|BT_TEXT_SYMBOLS_PRINT|BT_TEXT_SYMBOLS_NOPRINT)) {
bspstore = bt->task + SIZE(task_struct);
if (tt->flags & THREAD_INFO)
bspstore += SIZE(thread_info);
bspstore = roundup(bspstore, sizeof(ulong));
}
return bspstore;
}
/*
* Get the ksp out of the task's thread_struct
*/
static ulong
ia64_get_thread_ksp(ulong task)
{
ulong ksp;
if (XEN_HYPER_MODE()) {
readmem(task + XEN_HYPER_OFFSET(vcpu_thread_ksp), KVADDR,
&ksp, sizeof(void *),
"vcpu thread ksp", FAULT_ON_ERROR);
} else {
readmem(task + OFFSET(task_struct_thread_ksp), KVADDR,
&ksp, sizeof(void *),
"thread_struct ksp", FAULT_ON_ERROR);
}
return ksp;
}
/*
* Return the switch_stack structure address of a task.
*/
ulong
ia64_get_switch_stack(ulong task)
{
ulong sw;
if (LKCD_DUMPFILE() && (sw = get_lkcd_switch_stack(task)))
return sw;
/*
* debug only: get panic switch_stack from the ELF header.
*/
if (CRASHDEBUG(3) && NETDUMP_DUMPFILE() &&
(sw = get_netdump_switch_stack(task)))
return sw;
if (DISKDUMP_DUMPFILE() && (sw = get_diskdump_switch_stack(task)))
return sw;
return (ia64_get_thread_ksp((ulong)(task)) + 16);
}
/*
* Translate a PTE, returning TRUE if the page is _PAGE_P.
* If a physaddr pointer is passed in, don't print anything.
*/
static int
ia64_translate_pte(ulong pte, void *physaddr, ulonglong unused)
{
int c, len1, len2, len3, others, page_present;
char buf[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
char ptebuf[BUFSIZE];
char physbuf[BUFSIZE];
char *arglist[MAXARGS];
char *ptr;
ulong paddr;
paddr = pte & _PFN_MASK;
page_present = !!(pte & (_PAGE_P | _PAGE_PROTNONE));
if (physaddr) {
*((ulong *)physaddr) = paddr;
return page_present;
}
sprintf(ptebuf, "%lx", pte);
len1 = MAX(strlen(ptebuf), strlen("PTE"));
fprintf(fp, "%s ", mkstring(buf, len1, CENTER|LJUST, "PTE"));
if (!page_present && pte) {
swap_location(pte, buf);
if ((c = parse_line(buf, arglist)) != 3)
error(FATAL, "cannot determine swap location\n");
len2 = MAX(strlen(arglist[0]), strlen("SWAP"));
len3 = MAX(strlen(arglist[2]), strlen("OFFSET"));
fprintf(fp, "%s %s\n",
mkstring(buf2, len2, CENTER|LJUST, "SWAP"),
mkstring(buf3, len3, CENTER|LJUST, "OFFSET"));
strcpy(buf2, arglist[0]);
strcpy(buf3, arglist[2]);
fprintf(fp, "%s %s %s\n",
mkstring(ptebuf, len1, CENTER|RJUST, NULL),
mkstring(buf2, len2, CENTER|RJUST, NULL),
mkstring(buf3, len3, CENTER|RJUST, NULL));
return page_present;
}
sprintf(physbuf, "%lx", paddr);
len2 = MAX(strlen(physbuf), strlen("PHYSICAL"));
fprintf(fp, "%s ", mkstring(buf, len2, CENTER|LJUST, "PHYSICAL"));
fprintf(fp, "FLAGS\n");
fprintf(fp, "%s %s ",
mkstring(ptebuf, len1, CENTER|RJUST, NULL),
mkstring(physbuf, len2, CENTER|RJUST, NULL));
fprintf(fp, "(");
others = 0;
if (pte) {
if (pte & _PAGE_P)
fprintf(fp, "%sP", others++ ? "|" : "");
switch (pte & _PAGE_MA_MASK)
{
case _PAGE_MA_WB:
ptr = "MA_WB";
break;
case _PAGE_MA_UC:
ptr = "MA_UC";
break;
case _PAGE_MA_UCE:
ptr = "MA_UCE";
break;
case _PAGE_MA_WC:
ptr = "MA_WC";
break;
case _PAGE_MA_NAT:
ptr = "MA_NAT";
break;
case (0x1 << 2):
ptr = "MA_UC";
break;
default:
ptr = "MA_RSV";
break;
}
fprintf(fp, "%s%s", others++ ? "|" : "", ptr);
switch (pte & _PAGE_PL_MASK)
{
case _PAGE_PL_0:
ptr = "PL_0";
break;
case _PAGE_PL_1:
ptr = "PL_1";
break;
case _PAGE_PL_2:
ptr = "PL_2";
break;
case _PAGE_PL_3:
ptr = "PL_3";
break;
}
fprintf(fp, "%s%s", others++ ? "|" : "", ptr);
switch (pte & _PAGE_AR_MASK)
{
case _PAGE_AR_R:
ptr = "AR_R";
break;
case _PAGE_AR_RX:
ptr = "AT_RX";
break;
case _PAGE_AR_RW:
ptr = "AR_RW";
break;
case _PAGE_AR_RWX:
ptr = "AR_RWX";
break;
case _PAGE_AR_R_RW:
ptr = "AR_R_RW";
break;
case _PAGE_AR_RX_RWX:
ptr = "AR_RX_RWX";
break;
case _PAGE_AR_RWX_RW:
ptr = "AR_RWX_RW";
break;
case _PAGE_AR_X_RX:
ptr = "AR_X_RX";
break;
}
fprintf(fp, "%s%s", others++ ? "|" : "", ptr);
if (pte & _PAGE_A)
fprintf(fp, "%sA", others++ ? "|" : "");
if (pte & _PAGE_D)
fprintf(fp, "%sD", others++ ? "|" : "");
if (pte & _PAGE_ED)
fprintf(fp, "%sED", others++ ? "|" : "");
if (pte & _PAGE_PROTNONE)
fprintf(fp, "%sPROTNONE", others++ ? "|" : "");
} else {
fprintf(fp, "no mapping");
}
fprintf(fp, ")\n");
return page_present;
}
/*
* Determine where vmalloc'd memory starts.
*/
static ulong
ia64_vmalloc_start(void)
{
return machdep->machspec->vmalloc_start;
}
/*
* Verify that an address is a task_struct address.
*/
static int
ia64_is_task_addr(ulong task)
{
int i;
if (IS_KVADDR(task) && (ALIGNED_STACK_OFFSET(task) == 0))
return TRUE;
for (i = 0; i < kt->cpus; i++)
if (task == tt->idle_threads[i])
return TRUE;
return FALSE;
}
/*
* Filter disassembly output if the output radix is not gdb's default 10
*/
static int
ia64_dis_filter(ulong vaddr, char *inbuf, unsigned int output_radix)
{
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char *colon, *p1, *p2;
int argc;
int revise_bracket, stop_bit;
char *argv[MAXARGS];
ulong value;
if (!inbuf)
return TRUE;
/*
* For some reason gdb can go off into the weeds translating text addresses,
* (on alpha -- not necessarily seen on ia64) so this routine both fixes the
* references as well as imposing the current output radix on the translations.
*/
console("IN: %s", inbuf);
colon = strstr(inbuf, ":");
if (colon) {
sprintf(buf1, "0x%lx <%s>", vaddr,
value_to_symstr(vaddr, buf2, output_radix));
sprintf(buf2, "%s%s", buf1, colon);
strcpy(inbuf, buf2);
}
strcpy(buf1, inbuf);
argc = parse_line(buf1, argv);
revise_bracket = stop_bit = 0;
if ((FIRSTCHAR(argv[argc-1]) == '<') &&
(LASTCHAR(argv[argc-1]) == '>')) {
revise_bracket = TRUE;
stop_bit = FALSE;
} else if ((FIRSTCHAR(argv[argc-1]) == '<') &&
strstr(argv[argc-1], ">;;")) {
revise_bracket = TRUE;
stop_bit = TRUE;
}
if (revise_bracket) {
p1 = rindex(inbuf, '<');
while ((p1 > inbuf) && !STRNEQ(p1, "0x"))
p1--;
if (!STRNEQ(p1, "0x"))
return FALSE;
if (!extract_hex(p1, &value, NULLCHAR, TRUE))
return FALSE;
sprintf(buf1, "0x%lx <%s>%s\n", value,
value_to_symstr(value, buf2, output_radix),
stop_bit ? ";;" : "");
sprintf(p1, "%s", buf1);
} else if (STRNEQ(argv[argc-2], "br.call.") &&
STRNEQ(argv[argc-1], "b0=0x")) {
/*
* Update module function calls of these formats:
*
* br.call.sptk.many b0=0xa0000000003d5e40;;
* br.call.sptk.many b0=0xa00000000001dfc0
*
* to show a bracketed function name if the destination
* address is a known symbol with no offset.
*/
if ((p1 = strstr(argv[argc-1], ";;")) &&
(p2 = strstr(inbuf, ";;\n"))) {
*p1 = NULLCHAR;
p1 = &argv[argc-1][3];
if (extract_hex(p1, &value, NULLCHAR, TRUE)) {
sprintf(buf1, " <%s>;;\n",
value_to_symstr(value, buf2,
output_radix));
if (IS_MODULE_VADDR(value) &&
!strstr(buf2, "+"))
sprintf(p2, "%s", buf1);
}
} else {
p1 = &argv[argc-1][3];
p2 = &LASTCHAR(inbuf);
if (extract_hex(p1, &value, '\n', TRUE)) {
sprintf(buf1, " <%s>\n",
value_to_symstr(value, buf2,
output_radix));
if (IS_MODULE_VADDR(value) &&
!strstr(buf2, "+"))
sprintf(p2, "%s", buf1);
}
}
}
console(" %s", inbuf);
return TRUE;
}
/*
* Format the pt_regs structure.
*/
enum pt_reg_names {
P_cr_ipsr, P_cr_iip, P_cr_ifs,
P_ar_unat, P_ar_pfs, P_ar_rsc, P_ar_rnat, P_ar_bspstore,
P_ar_ccv, P_ar_fpsr,
P_pr, P_loadrs,
P_b0, P_b6, P_b7,
P_r1, P_r2, P_r3, P_r8, P_r9, P_r10, P_r11, P_r12, P_r13,
P_r14, P_r15, P_r16, P_r17, P_r18, P_r19, P_r20, P_r21,
P_r22, P_r23, P_r24, P_r25, P_r26, P_r27, P_r28, P_r29,
P_r30, P_r31,
P_f6_lo, P_f6_hi,
P_f7_lo, P_f7_hi,
P_f8_lo, P_f8_hi,
P_f9_lo, P_f9_hi,
P_f10_lo, P_f10_hi,
P_f11_lo, P_f11_hi,
NUM_PT_REGS};
void
ia64_exception_frame(ulong addr, struct bt_info *bt)
{
char buf[BUFSIZE], *p, *p1;
int fval;
ulong value1, value2;
ulong eframe[NUM_PT_REGS];
console("ia64_exception_frame: pt_regs: %lx\n", addr);
if (bt->debug)
CRASHDEBUG_RESTORE();
CRASHDEBUG_SUSPEND(0);
BZERO(&eframe, sizeof(ulong) * NUM_PT_REGS);
open_tmpfile();
if (XEN_HYPER_MODE())
dump_struct("cpu_user_regs", addr, RADIX(16));
else
dump_struct("pt_regs", addr, RADIX(16));
rewind(pc->tmpfile);
fval = 0;
while (fgets(buf, BUFSIZE, pc->tmpfile)) {
if (strstr(buf, "f6 = ")) {
fval = 6;
continue;
}
if (strstr(buf, "f7 = ")) {
fval = 7;
continue;
}
if (strstr(buf, "f8 = ")) {
fval = 8;
continue;
}
if (strstr(buf, "f9 = ")) {
fval = 9;
continue;
}
if (strstr(buf, "f10 = ")) {
fval = 10;
continue;
}
if (strstr(buf, "f11 = ")) {
fval = 11;
continue;
}
if (!strstr(buf, "0x"))
continue;
if (fval) {
p = strstr(buf, "0x");
if ((p1 = strstr(p, "}")))
*p1 = NULLCHAR;
extract_hex(p, &value1, ',', TRUE);
p = strstr(buf, ",");
extract_hex(p, &value2, NULLCHAR, FALSE);
switch (fval)
{
case 6:
eframe[P_f6_lo] = value1;
eframe[P_f6_hi] = value2;
break;
case 7:
eframe[P_f7_lo] = value1;
eframe[P_f7_hi] = value2;
break;
case 8:
eframe[P_f8_lo] = value1;
eframe[P_f8_hi] = value2;
break;
case 9:
eframe[P_f9_lo] = value1;
eframe[P_f9_hi] = value2;
break;
case 10:
eframe[P_f10_lo] = value1;
eframe[P_f10_hi] = value2;
break;
case 11:
eframe[P_f11_lo] = value1;
eframe[P_f11_hi] = value2;
break;
}
fval = 0;
continue;
}
strip_comma(clean_line(buf));
p = strstr(buf, " = ");
extract_hex(p, &value1, NULLCHAR, FALSE);
if (strstr(buf, "cr_ipsr = ")) {
eframe[P_cr_ipsr] = value1;
}
if (strstr(buf, "cr_iip = ")) {
eframe[P_cr_iip] = value1;
}
if (strstr(buf, "cr_ifs = ")) {
eframe[P_cr_ifs] = value1;
}
if (strstr(buf, "ar_unat = ")) {
eframe[P_ar_unat] = value1;
}
if (strstr(buf, "ar_pfs = ")) {
eframe[P_ar_pfs] = value1;
}
if (strstr(buf, "ar_rsc = ")) {
eframe[P_ar_rsc] = value1;
}
if (strstr(buf, "ar_rnat = ")) {
eframe[P_ar_rnat] = value1;
}
if (strstr(buf, "ar_bspstore = ")) {
eframe[P_ar_bspstore] = value1;
}
if (strstr(buf, "ar_ccv = ")) {
eframe[P_ar_ccv] = value1;
}
if (strstr(buf, "ar_fpsr = ")) {
eframe[P_ar_fpsr] = value1;
}
if (strstr(buf, "pr = ")) {
eframe[P_pr] = value1;
}
if (strstr(buf, "loadrs = ")) {
eframe[P_loadrs] = value1;
}
if (strstr(buf, "b0 = ")) {
eframe[P_b0] = value1;
}
if (strstr(buf, "b6 = ")) {
eframe[P_b6] = value1;
}
if (strstr(buf, "b7 = ")) {
eframe[P_b7] = value1;
}
if (strstr(buf, "r1 = ")) {
eframe[P_r1] = value1;
}
if (strstr(buf, "r2 = ")) {
eframe[P_r2] = value1;
}
if (strstr(buf, "r3 = ")) {
eframe[P_r3] = value1;
}
if (strstr(buf, "r8 = ")) {
eframe[P_r8] = value1;
}
if (strstr(buf, "r9 = ")) {
eframe[P_r9] = value1;
}
if (strstr(buf, "r10 = ")) {
eframe[P_r10] = value1;
}
if (strstr(buf, "r11 = ")) {
eframe[P_r11] = value1;
}
if (strstr(buf, "r12 = ")) {
eframe[P_r12] = value1;
}
if (strstr(buf, "r13 = ")) {
eframe[P_r13] = value1;
}
if (strstr(buf, "r14 = ")) {
eframe[P_r14] = value1;
}
if (strstr(buf, "r15 = ")) {
eframe[P_r15] = value1;
}
if (strstr(buf, "r16 = ")) {
eframe[P_r16] = value1;
}
if (strstr(buf, "r17 = ")) {
eframe[P_r17] = value1;
}
if (strstr(buf, "r18 = ")) {
eframe[P_r18] = value1;
}
if (strstr(buf, "r19 = ")) {
eframe[P_r19] = value1;
}
if (strstr(buf, "r20 = ")) {
eframe[P_r20] = value1;
}
if (strstr(buf, "r21 = ")) {
eframe[P_r21] = value1;
}
if (strstr(buf, "r22 = ")) {
eframe[P_r22] = value1;
}
if (strstr(buf, "r23 = ")) {
eframe[P_r23] = value1;
}
if (strstr(buf, "r24 = ")) {
eframe[P_r24] = value1;
}
if (strstr(buf, "r25 = ")) {
eframe[P_r25] = value1;
}
if (strstr(buf, "r26 = ")) {
eframe[P_r26] = value1;
}
if (strstr(buf, "r27 = ")) {
eframe[P_r27] = value1;
}
if (strstr(buf, "r28 = ")) {
eframe[P_r28] = value1;
}
if (strstr(buf, "r29 = ")) {
eframe[P_r29] = value1;
}
if (strstr(buf, "r30 = ")) {
eframe[P_r30] = value1;
}
if (strstr(buf, "r31 = ")) {
eframe[P_r31] = value1;
}
}
close_tmpfile();
fprintf(fp, " EFRAME: %lx\n", addr);
if (bt->flags & BT_INCOMPLETE_USER_EFRAME) {
fprintf(fp,
" [exception frame incomplete -- check salinfo for complete context]\n");
bt->flags &= ~BT_INCOMPLETE_USER_EFRAME;
}
fprintf(fp, " B0: %016lx CR_IIP: %016lx\n",
eframe[P_b0], eframe[P_cr_iip]);
/**
if (is_kernel_text(eframe[P_cr_iip]))
fprintf(fp, "<%s>",
value_to_symstr(eframe[P_cr_iip], buf, 0));
fprintf(fp, "\n");
**/
fprintf(fp, " CR_IPSR: %016lx CR_IFS: %016lx\n",
eframe[P_cr_ipsr], eframe[P_cr_ifs]);
fprintf(fp, " AR_PFS: %016lx AR_RSC: %016lx\n",
eframe[P_ar_pfs], eframe[P_ar_rsc]);
fprintf(fp, " AR_UNAT: %016lx AR_RNAT: %016lx\n",
eframe[P_ar_unat], eframe[P_ar_rnat]);
fprintf(fp, " AR_CCV: %016lx AR_FPSR: %016lx\n",
eframe[P_ar_ccv], eframe[P_ar_fpsr]);
fprintf(fp, " LOADRS: %016lx AR_BSPSTORE: %016lx\n",
eframe[P_loadrs], eframe[P_ar_bspstore]);
fprintf(fp, " B6: %016lx B7: %016lx\n",
eframe[P_b6], eframe[P_b7]);
fprintf(fp, " PR: %016lx R1: %016lx\n",
eframe[P_pr], eframe[P_r1]);
fprintf(fp, " R2: %016lx R3: %016lx\n",
eframe[P_r2], eframe[P_r3]);
fprintf(fp, " R8: %016lx R9: %016lx\n",
eframe[P_r8], eframe[P_r9]);
fprintf(fp, " R10: %016lx R11: %016lx\n",
eframe[P_r10], eframe[P_r11]);
fprintf(fp, " R12: %016lx R13: %016lx\n",
eframe[P_r12], eframe[P_r13]);
fprintf(fp, " R14: %016lx R15: %016lx\n",
eframe[P_r14], eframe[P_r15]);
fprintf(fp, " R16: %016lx R17: %016lx\n",
eframe[P_r16], eframe[P_r17]);
fprintf(fp, " R18: %016lx R19: %016lx\n",
eframe[P_r18], eframe[P_r19]);
fprintf(fp, " R20: %016lx R21: %016lx\n",
eframe[P_r20], eframe[P_r21]);
fprintf(fp, " R22: %016lx R23: %016lx\n",
eframe[P_r22], eframe[P_r23]);
fprintf(fp, " R24: %016lx R25: %016lx\n",
eframe[P_r24], eframe[P_r25]);
fprintf(fp, " R26: %016lx R27: %016lx\n",
eframe[P_r26], eframe[P_r27]);
fprintf(fp, " R28: %016lx R29: %016lx\n",
eframe[P_r28], eframe[P_r29]);
fprintf(fp, " R30: %016lx R31: %016lx\n",
eframe[P_r30], eframe[P_r31]);
fprintf(fp, " F6: %05lx%016lx ",
eframe[P_f6_hi], eframe[P_f6_lo]);
fprintf(fp, " F7: %05lx%016lx\n",
eframe[P_f7_hi], eframe[P_f7_lo]);
fprintf(fp, " F8: %05lx%016lx ",
eframe[P_f8_hi], eframe[P_f8_lo]);
fprintf(fp, " F9: %05lx%016lx\n",
eframe[P_f9_hi], eframe[P_f9_lo]);
if (machdep->flags & NEW_UNW_V3) {
fprintf(fp, " F10: %05lx%016lx ",
eframe[P_f10_hi], eframe[P_f10_lo]);
fprintf(fp, " F11: %05lx%016lx\n",
eframe[P_f11_hi], eframe[P_f11_lo]);
}
CRASHDEBUG_RESTORE();
if (bt->debug)
CRASHDEBUG_SUSPEND(bt->debug);
}
enum ss_reg_names {
S_caller_unat, S_ar_fpsr,
S_f2_lo, S_f2_hi,
S_f3_lo, S_f3_hi,
S_f4_lo, S_f4_hi,
S_f5_lo, S_f5_hi,
S_f10_lo, S_f10_hi,
S_f11_lo, S_f11_hi,
S_f12_lo, S_f12_hi,
S_f13_lo, S_f13_hi,
S_f14_lo, S_f14_hi,
S_f15_lo, S_f15_hi,
S_f16_lo, S_f16_hi,
S_f17_lo, S_f17_hi,
S_f18_lo, S_f18_hi,
S_f19_lo, S_f19_hi,
S_f20_lo, S_f20_hi,
S_f21_lo, S_f21_hi,
S_f22_lo, S_f22_hi,
S_f23_lo, S_f23_hi,
S_f24_lo, S_f24_hi,
S_f25_lo, S_f25_hi,
S_f26_lo, S_f26_hi,
S_f27_lo, S_f27_hi,
S_f28_lo, S_f28_hi,
S_f29_lo, S_f29_hi,
S_f30_lo, S_f30_hi,
S_f31_lo, S_f31_hi,
S_r4, S_r5, S_r6, S_r7,
S_b0, S_b1, S_b2, S_b3, S_b4, S_b5,
S_ar_pfs, S_ar_lc, S_ar_unat, S_ar_rnat, S_ar_bspstore, S_pr,
NUM_SS_REGS };
/*
* Format the switch_stack structure.
*/
static void
ia64_dump_switch_stack(ulong task, ulong flag)
{
ulong addr;
char buf[BUFSIZE], *p;
int fval;
ulong value1, value2;
ulong ss[NUM_SS_REGS];
addr = SWITCH_STACK_ADDR(task);
BZERO(&ss, sizeof(ulong) * NUM_SS_REGS);
open_tmpfile();
dump_struct("switch_stack", addr, RADIX(16));
rewind(pc->tmpfile);
fval = 0;
while (fgets(buf, BUFSIZE, pc->tmpfile)) {
if (strstr(buf, "f2 = ")) {
fval = 2;
continue;
}
if (strstr(buf, "f3 = ")) {
fval = 3;
continue;
}
if (strstr(buf, "f4 = ")) {
fval = 4;
continue;
}
if (strstr(buf, "f5 = ")) {
fval = 5;
continue;
}
if (strstr(buf, "f10 = ")) {
fval = 10;
continue;
}
if (strstr(buf, "f11 = ")) {
fval = 11;
continue;
}
if (strstr(buf, "f12 = ")) {
fval = 12;
continue;
}
if (strstr(buf, "f13 = ")) {
fval = 13;
continue;
}
if (strstr(buf, "f14 = ")) {
fval = 14;
continue;
}
if (strstr(buf, "f15 = ")) {
fval = 15;
continue;
}
if (strstr(buf, "f16 = ")) {
fval = 16;
continue;
}
if (strstr(buf, "f17 = ")) {
fval = 17;
continue;
}
if (strstr(buf, "f18 = ")) {
fval = 18;
continue;
}
if (strstr(buf, "f19 = ")) {
fval = 19;
continue;
}
if (strstr(buf, "f20 = ")) {
fval = 20;
continue;
}
if (strstr(buf, "f21 = ")) {
fval = 21;
continue;
}
if (strstr(buf, "f22 = ")) {
fval = 22;
continue;
}
if (strstr(buf, "f23 = ")) {
fval = 23;
continue;
}
if (strstr(buf, "f24 = ")) {
fval = 24;
continue;
}
if (strstr(buf, "f25 = ")) {
fval = 25;
continue;
}
if (strstr(buf, "f26 = ")) {
fval = 26;
continue;
}
if (strstr(buf, "f27 = ")) {
fval = 27;
continue;
}
if (strstr(buf, "f28 = ")) {
fval = 28;
continue;
}
if (strstr(buf, "f29 = ")) {
fval = 29;
continue;
}
if (strstr(buf, "f30 = ")) {
fval = 30;
continue;
}
if (strstr(buf, "f31 = ")) {
fval = 31;
continue;
}
if (!strstr(buf, "0x"))
continue;
if (fval) {
p = strstr(buf, "0x");
extract_hex(p, &value1, ',', TRUE);
p = strstr(buf, ",");
extract_hex(p, &value2, '}', FALSE);
switch (fval)
{
case 2:
ss[S_f2_lo] = value1;
ss[S_f2_hi] = value2;
break;
case 3:
ss[S_f3_lo] = value1;
ss[S_f3_hi] = value2;
break;
case 4:
ss[S_f4_lo] = value1;
ss[S_f4_hi] = value2;
break;
case 5:
ss[S_f5_lo] = value1;
ss[S_f5_hi] = value2;
break;
case 10:
ss[S_f10_lo] = value1;
ss[S_f10_hi] = value2;
break;
case 11:
ss[S_f11_lo] = value1;
ss[S_f11_hi] = value2;
break;
case 12:
ss[S_f12_lo] = value1;
ss[S_f12_hi] = value2;
break;
case 13:
ss[S_f13_lo] = value1;
ss[S_f13_hi] = value2;
break;
case 14:
ss[S_f14_lo] = value1;
ss[S_f14_hi] = value2;
break;
case 15:
ss[S_f15_lo] = value1;
ss[S_f15_hi] = value2;
break;
case 16:
ss[S_f16_lo] = value1;
ss[S_f16_hi] = value2;
break;
case 17:
ss[S_f17_lo] = value1;
ss[S_f17_hi] = value2;
break;
case 18:
ss[S_f18_lo] = value1;
ss[S_f18_hi] = value2;
break;
case 19:
ss[S_f19_lo] = value1;
ss[S_f19_hi] = value2;
break;
case 20:
ss[S_f20_lo] = value1;
ss[S_f20_hi] = value2;
break;
case 21:
ss[S_f21_lo] = value1;
ss[S_f21_hi] = value2;
break;
case 22:
ss[S_f22_lo] = value1;
ss[S_f22_hi] = value2;
break;
case 23:
ss[S_f23_lo] = value1;
ss[S_f23_hi] = value2;
break;
case 24:
ss[S_f24_lo] = value1;
ss[S_f24_hi] = value2;
break;
case 25:
ss[S_f25_lo] = value1;
ss[S_f25_hi] = value2;
break;
case 26:
ss[S_f26_lo] = value1;
ss[S_f26_hi] = value2;
break;
case 27:
ss[S_f27_lo] = value1;
ss[S_f27_hi] = value2;
break;
case 28:
ss[S_f28_lo] = value1;
ss[S_f28_hi] = value2;
break;
case 29:
ss[S_f29_lo] = value1;
ss[S_f29_hi] = value2;
break;
case 30:
ss[S_f30_lo] = value1;
ss[S_f30_hi] = value2;
break;
case 31:
ss[S_f31_lo] = value1;
ss[S_f31_hi] = value2;
break;
}
fval = 0;
continue;
}
strip_comma(clean_line(buf));
p = strstr(buf, " = ");
extract_hex(p, &value1, NULLCHAR, FALSE);
if (strstr(buf, "caller_unat = ")) {
ss[S_caller_unat] = value1;
}
if (strstr(buf, "ar_fpsr = ")) {
ss[S_ar_fpsr] = value1;
}
if (strstr(buf, "r4 = ")) {
ss[S_r4] = value1;
}
if (strstr(buf, "r5 = ")) {
ss[S_r5] = value1;
}
if (strstr(buf, "r6 = ")) {
ss[S_r6] = value1;
}
if (strstr(buf, "r7 = ")) {
ss[S_r7] = value1;
}
if (strstr(buf, "b0 = ")) {
ss[S_b0] = value1;
}
if (strstr(buf, "b1 = ")) {
ss[S_b1] = value1;
}
if (strstr(buf, "b2 = ")) {
ss[S_b2] = value1;
}
if (strstr(buf, "b3 = ")) {
ss[S_b3] = value1;
}
if (strstr(buf, "b4 = ")) {
ss[S_b4] = value1;
}
if (strstr(buf, "b5 = ")) {
ss[S_b5] = value1;
}
if (strstr(buf, "ar_pfs = ")) {
ss[S_ar_pfs] = value1;
}
if (strstr(buf, "ar_lc = ")) {
ss[S_ar_lc] = value1;
}
if (strstr(buf, "ar_unat = ")) {
ss[S_ar_unat] = value1;
}
if (strstr(buf, "ar_rnat = ")) {
ss[S_ar_rnat] = value1;
}
if (strstr(buf, "ar_bspstore = ")) {
ss[S_ar_bspstore] = value1;
}
if (strstr(buf, "pr = ")) {
ss[S_pr] = value1;
}
}
close_tmpfile();
fprintf(fp, "SWITCH_STACK: %lx\n", addr);
fprintf(fp, " B0: %016lx B1: %016lx\n",
ss[S_b0], ss[S_b1]);
fprintf(fp, " B2: %016lx B3: %016lx\n",
ss[S_b2], ss[S_b3]);
fprintf(fp, " B4: %016lx B5: %016lx\n",
ss[S_b4], ss[S_b5]);
fprintf(fp, " AR_PFS: %016lx AR_LC: %016lx\n",
ss[S_ar_pfs], ss[S_ar_lc]);
fprintf(fp, " AR_UNAT: %016lx AR_RNAT: %016lx\n",
ss[S_ar_unat], ss[S_ar_rnat]);
fprintf(fp, " PR: %016lx AR_BSPSTORE: %016lx\n",
ss[S_pr], ss[S_ar_bspstore]);
fprintf(fp, " AR_FPSR: %016lx CALLER_UNAT: %016lx\n",
ss[S_ar_fpsr], ss[S_caller_unat]);
fprintf(fp, " R4: %016lx R5: %016lx\n",
ss[S_r4], ss[S_r5]);
fprintf(fp, " R6: %016lx R7: %016lx\n",
ss[S_r6], ss[S_r7]);
fprintf(fp, " F2: %05lx%016lx ", ss[S_f2_hi], ss[S_f2_lo]);
fprintf(fp, " F3: %05lx%016lx\n", ss[S_f3_hi], ss[S_f3_lo]);
fprintf(fp, " F4: %05lx%016lx ", ss[S_f4_hi], ss[S_f4_lo]);
fprintf(fp, " F5: %05lx%016lx\n", ss[S_f5_hi], ss[S_f5_lo]);
fprintf(fp, " F10: %05lx%016lx ", ss[S_f10_hi], ss[S_f10_lo]);
fprintf(fp, " F11: %05lx%016lx\n", ss[S_f11_hi], ss[S_f11_lo]);
fprintf(fp, " F12: %05lx%016lx ", ss[S_f12_hi], ss[S_f12_lo]);
fprintf(fp, " F13: %05lx%016lx\n", ss[S_f13_hi], ss[S_f13_lo]);
fprintf(fp, " F14: %05lx%016lx ", ss[S_f14_hi], ss[S_f14_lo]);
fprintf(fp, " F15: %05lx%016lx\n", ss[S_f15_hi], ss[S_f15_lo]);
fprintf(fp, " F16: %05lx%016lx ", ss[S_f16_hi], ss[S_f16_lo]);
fprintf(fp, " F17: %05lx%016lx\n", ss[S_f17_hi], ss[S_f17_lo]);
fprintf(fp, " F18: %05lx%016lx ", ss[S_f18_hi], ss[S_f18_lo]);
fprintf(fp, " F19: %05lx%016lx\n", ss[S_f19_hi], ss[S_f19_lo]);
fprintf(fp, " F20: %05lx%016lx ", ss[S_f20_hi], ss[S_f20_lo]);
fprintf(fp, " F21: %05lx%016lx\n", ss[S_f21_hi], ss[S_f21_lo]);
fprintf(fp, " F22: %05lx%016lx ", ss[S_f22_hi], ss[S_f22_lo]);
fprintf(fp, " F23: %05lx%016lx\n", ss[S_f23_hi], ss[S_f23_lo]);
fprintf(fp, " F24: %05lx%016lx ", ss[S_f24_hi], ss[S_f24_lo]);
fprintf(fp, " F25: %05lx%016lx\n", ss[S_f25_hi], ss[S_f25_lo]);
fprintf(fp, " F26: %05lx%016lx ", ss[S_f26_hi], ss[S_f26_lo]);
fprintf(fp, " F27: %05lx%016lx\n", ss[S_f27_hi], ss[S_f27_lo]);
fprintf(fp, " F28: %05lx%016lx ", ss[S_f28_hi], ss[S_f28_lo]);
fprintf(fp, " F29: %05lx%016lx\n", ss[S_f29_hi], ss[S_f29_lo]);
fprintf(fp, " F30: %05lx%016lx ", ss[S_f30_hi], ss[S_f30_lo]);
fprintf(fp, " F31: %05lx%016lx\n", ss[S_f31_hi], ss[S_f31_lo]);
}
/*
* Override smp_num_cpus if possible and necessary.
*/
int
ia64_get_smp_cpus(void)
{
int cpus;
if ((cpus = get_cpus_online()))
return MAX(cpus, get_highest_cpu_online()+1);
else
return kt->cpus;
}
/*
* Machine dependent command.
*/
void
ia64_cmd_mach(void)
{
int c, cflag, mflag;
unsigned int radix;
cflag = mflag = radix = 0;
while ((c = getopt(argcnt, args, "cmxd")) != EOF) {
switch(c)
{
case 'c':
cflag++;
break;
case 'm':
mflag++;
ia64_display_memmap();
break;
case 'x':
if (radix == 10)
error(FATAL,
"-d and -x are mutually exclusive\n");
radix = 16;
break;
case 'd':
if (radix == 16)
error(FATAL,
"-d and -x are mutually exclusive\n");
radix = 10;
break;
default:
argerrs++;
break;
}
}
if (argerrs)
cmd_usage(pc->curcmd, SYNOPSIS);
if (cflag)
ia64_display_cpu_data(radix);
if (!cflag && !mflag)
ia64_display_machine_stats();
}
/*
* "mach" command output.
*/
static void
ia64_display_machine_stats(void)
{
struct new_utsname *uts;
char buf[BUFSIZE];
ulong mhz;
uts = &kt->utsname;
fprintf(fp, " MACHINE TYPE: %s\n", uts->machine);
fprintf(fp, " MEMORY SIZE: %s\n", get_memory_size(buf));
fprintf(fp, " CPUS: %d\n", kt->cpus);
if (!STREQ(kt->hypervisor, "(undetermined)") &&
!STREQ(kt->hypervisor, "bare hardware"))
fprintf(fp, " HYPERVISOR: %s\n", kt->hypervisor);
fprintf(fp, " PROCESSOR SPEED: ");
if ((mhz = machdep->processor_speed()))
fprintf(fp, "%ld Mhz\n", mhz);
else
fprintf(fp, "(unknown)\n");
fprintf(fp, " HZ: %d\n", machdep->hz);
fprintf(fp, " PAGE SIZE: %d\n", PAGESIZE());
// fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size());
fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE());
fprintf(fp, " KERNEL CACHED REGION: %lx\n",
(ulong)KERNEL_CACHED_REGION << REGION_SHIFT);
fprintf(fp, " KERNEL UNCACHED REGION: %lx\n",
(ulong)KERNEL_UNCACHED_REGION << REGION_SHIFT);
fprintf(fp, " KERNEL VMALLOC REGION: %lx\n",
(ulong)KERNEL_VMALLOC_REGION << REGION_SHIFT);
fprintf(fp, " USER DATA/STACK REGION: %lx\n",
(ulong)USER_STACK_REGION << REGION_SHIFT);
fprintf(fp, " USER DATA/STACK REGION: %lx\n",
(ulong)USER_DATA_REGION << REGION_SHIFT);
fprintf(fp, " USER TEXT REGION: %lx\n",
(ulong)USER_TEXT_REGION << REGION_SHIFT);
fprintf(fp, " USER SHARED MEMORY REGION: %lx\n",
(ulong)USER_SHMEM_REGION << REGION_SHIFT);
fprintf(fp, "USER IA32 EMULATION REGION: %016lx\n",
(ulong)USER_IA32_EMUL_REGION << REGION_SHIFT);
}
static void
ia64_display_cpu_data(unsigned int radix)
{
int cpu;
ulong cpu_data;
int array_location_known;
struct syment *sp;
if (!(cpu_data = machdep->machspec->cpu_data_address)) {
error(FATAL, "cannot find cpuinfo_ia64 location\n");
return;
}
array_location_known = per_cpu_symbol_search("per_cpu__cpu_info") ||
symbol_exists("cpu_data") || symbol_exists("_cpu_data");
for (cpu = 0; cpu < kt->cpus; cpu++) {
fprintf(fp, "%sCPU %d: %s\n", cpu ? "\n" : "", cpu,
array_location_known ? "" : "(boot)");
dump_struct("cpuinfo_ia64", cpu_data, radix);
if (!array_location_known)
break;
if ((sp = per_cpu_symbol_search("per_cpu__cpu_info"))) {
if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF))
cpu_data = sp->value +
kt->__per_cpu_offset[cpu+1];
else
break; /* we've already done cpu 0 */
} else
cpu_data += SIZE(cpuinfo_ia64);
}
}
/*
* Dump the EFI memory map.
*/
static void
ia64_display_memmap(void)
{
int i, others;
struct efi_memory_desc_t *desc;
struct machine_specific *ms;
char *map;
ms = &ia64_machine_specific;
map = ms->ia64_memmap;
if (!map) {
check_mem_limit();
error(FATAL, "efi_mmap not accessible\n");
}
fprintf(fp,
" PHYSICAL ADDRESS RANGE TYPE / ATTRIBUTE / [ACCESS]\n");
for (i = 0; i < ms->efi_memmap_size/ms->efi_memdesc_size; i++) {
desc = (struct efi_memory_desc_t *)map;
fprintf(fp, "%016lx - %016lx ",
desc->phys_addr, desc->phys_addr +
(desc->num_pages * (1 << EFI_PAGE_SHIFT)));
switch (desc->type)
{
case EFI_RESERVED_TYPE:
fprintf(fp, "%s", "RESERVED_TYPE"); break;
case EFI_LOADER_CODE:
fprintf(fp, "%s", "LOADER_CODE"); break;
case EFI_LOADER_DATA:
fprintf(fp, "%s", "LOADER_DATA"); break;
case EFI_BOOT_SERVICES_CODE:
fprintf(fp, "%s", "BOOT_SERVICES_CODE"); break;
case EFI_BOOT_SERVICES_DATA:
fprintf(fp, "%s", "BOOT_SERVICES_DATA"); break;
case EFI_RUNTIME_SERVICES_CODE:
fprintf(fp, "%s", "RUNTIME_SERVICES_CODE"); break;
case EFI_RUNTIME_SERVICES_DATA:
fprintf(fp, "%s", "RUNTIME_SERVICES_DATA"); break;
case EFI_CONVENTIONAL_MEMORY:
fprintf(fp, "%s", "CONVENTIONAL_MEMORY"); break;
case EFI_UNUSABLE_MEMORY:
fprintf(fp, "%s", "UNUSABLE_MEMORY"); break;
case EFI_ACPI_RECLAIM_MEMORY:
fprintf(fp, "%s", "ACPI_RECLAIM_MEMORY"); break;
case EFI_ACPI_MEMORY_NVS:
fprintf(fp, "%s", "ACPI_MEMORY_NVS"); break;
case EFI_MEMORY_MAPPED_IO:
fprintf(fp, "%s", "MEMORY_MAPPED_IO"); break;
case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
fprintf(fp, "%s", "MEMORY_MAPPED_IO_PORT_SPACE");
break;
case EFI_PAL_CODE:
fprintf(fp, "%s", "PAL_CODE"); break;
default:
fprintf(fp, "%s", "(unknown type)"); break;
}
fprintf(fp, " ");
others = 0;
if (desc->attribute & EFI_MEMORY_UC)
fprintf(fp, "%sUC", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_WC)
fprintf(fp, "%sWC", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_WT)
fprintf(fp, "%sWT", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_WB)
fprintf(fp, "%sWB", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_WP)
fprintf(fp, "%sWP", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_RP)
fprintf(fp, "%sRP", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_XP)
fprintf(fp, "%sXP", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_RUNTIME)
fprintf(fp, "%sRUNTIME", others++ ? "|" : "");
fprintf(fp, " %s", ia64_available_memory(desc) ?
"[available]" : "");
switch (VADDR_REGION(desc->virt_addr))
{
case KERNEL_UNCACHED_REGION:
fprintf(fp, "[R6]\n");
break;
case KERNEL_CACHED_REGION:
fprintf(fp, "[R7]\n");
break;
default:
fprintf(fp, "\n");
}
if (!CRASHDEBUG(1))
goto next_desc;
fprintf(fp,
"physical: %016lx %dk pages: %ld virtual: %016lx\n",
desc->phys_addr, (1 << EFI_PAGE_SHIFT)/1024,
desc->num_pages, desc->virt_addr);
fprintf(fp, "type: ");
switch (desc->type)
{
case EFI_RESERVED_TYPE:
fprintf(fp, "%-27s", "RESERVED_TYPE"); break;
case EFI_LOADER_CODE:
fprintf(fp, "%-27s", "LOADER_CODE"); break;
case EFI_LOADER_DATA:
fprintf(fp, "%-27s", "LOADER_DATA"); break;
case EFI_BOOT_SERVICES_CODE:
fprintf(fp, "%-27s", "BOOT_SERVICES_CODE"); break;
case EFI_BOOT_SERVICES_DATA:
fprintf(fp, "%-27s", "BOOT_SERVICES_DATA"); break;
case EFI_RUNTIME_SERVICES_CODE:
fprintf(fp, "%-27s", "RUNTIME_SERVICES_CODE"); break;
case EFI_RUNTIME_SERVICES_DATA:
fprintf(fp, "%-27s", "RUNTIME_SERVICES_DATA"); break;
case EFI_CONVENTIONAL_MEMORY:
fprintf(fp, "%-27s", "CONVENTIONAL_MEMORY"); break;
case EFI_UNUSABLE_MEMORY:
fprintf(fp, "%-27s", "UNUSABLE_MEMORY"); break;
case EFI_ACPI_RECLAIM_MEMORY:
fprintf(fp, "%-27s", "ACPI_RECLAIM_MEMORY"); break;
case EFI_ACPI_MEMORY_NVS:
fprintf(fp, "%-27s", "ACPI_MEMORY_NVS"); break;
case EFI_MEMORY_MAPPED_IO:
fprintf(fp, "%-27s", "MEMORY_MAPPED_IO"); break;
case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
fprintf(fp, "%-27s", "MEMORY_MAPPED_IO_PORT_SPACE");
break;
case EFI_PAL_CODE:
fprintf(fp, "%-27s", "PAL_CODE"); break;
default:
fprintf(fp, "%-27s", "(unknown type)"); break;
}
fprintf(fp, " attribute: (");
others = 0;
if (desc->attribute & EFI_MEMORY_UC)
fprintf(fp, "%sUC", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_WC)
fprintf(fp, "%sWC", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_WT)
fprintf(fp, "%sWT", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_WB)
fprintf(fp, "%sWB", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_WP)
fprintf(fp, "%sWP", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_RP)
fprintf(fp, "%sRP", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_XP)
fprintf(fp, "%sXP", others++ ? "|" : "");
if (desc->attribute & EFI_MEMORY_RUNTIME)
fprintf(fp, "%sRUNTIME", others++ ? "|" : "");
fprintf(fp, ") %s\n", ia64_available_memory(desc) ?
"[available]" : "");
next_desc:
map += ms->efi_memdesc_size;
}
}
static int
ia64_available_memory(struct efi_memory_desc_t *desc)
{
if (desc->attribute & EFI_MEMORY_WB) {
switch (desc->type) {
case EFI_LOADER_CODE:
case EFI_LOADER_DATA:
case EFI_BOOT_SERVICES_CODE:
case EFI_BOOT_SERVICES_DATA:
case EFI_CONVENTIONAL_MEMORY:
return TRUE;
}
}
return FALSE;
}
/*
* Make a copy of the memmap descriptor array.
*/
static void
ia64_create_memmap(void)
{
struct machine_specific *ms;
uint64_t ia64_boot_param, efi_memmap;
ulong num_physpages;
char *memmap;
ms = &ia64_machine_specific;
ms->ia64_memmap = NULL;
if (symbol_exists("num_physpages")) {
get_symbol_data("num_physpages", sizeof(ulong), &num_physpages);
machdep->memsize = num_physpages * PAGESIZE();
}
if (!symbol_exists("ia64_boot_param"))
return;
if ((ms->mem_limit = check_mem_limit()))
machdep->flags |= MEM_LIMIT;
get_symbol_data("ia64_boot_param", sizeof(void *), &ia64_boot_param);
if ((ms->mem_limit && (ia64_VTOP(ia64_boot_param) >= ms->mem_limit)) ||
!readmem(ia64_boot_param+
MEMBER_OFFSET("ia64_boot_param", "efi_memmap"),
KVADDR, &efi_memmap, sizeof(uint64_t), "efi_memmap",
QUIET|RETURN_ON_ERROR)) {
if (!XEN() || CRASHDEBUG(1))
error(WARNING, "cannot read ia64_boot_param: "
"memory verification will not be performed\n\n");
return;
}
readmem(ia64_boot_param+MEMBER_OFFSET("ia64_boot_param",
"efi_memmap_size"), KVADDR, &ms->efi_memmap_size,
sizeof(uint64_t), "efi_memmap_size", FAULT_ON_ERROR);
readmem(ia64_boot_param+MEMBER_OFFSET("ia64_boot_param",
"efi_memdesc_size"), KVADDR, &ms->efi_memdesc_size,
sizeof(uint64_t), "efi_memdesc_size", FAULT_ON_ERROR);
if (!(memmap = (char *) malloc(ms->efi_memmap_size))) {
error(WARNING, "cannot malloc ia64_memmap\n");
return;
}
if ((ms->mem_limit && (efi_memmap >= ms->mem_limit)) ||
!readmem(PTOV(efi_memmap), KVADDR, memmap,
ms->efi_memmap_size, "efi_mmap contents",
QUIET|RETURN_ON_ERROR)) {
if (!XEN() || (XEN() && CRASHDEBUG(1)))
error(WARNING, "cannot read efi_mmap: "
"EFI memory verification will not be performed\n\n");
free(memmap);
return;
}
ms->ia64_memmap = memmap;
}
/*
* Kernel pages may cross EFI memmap boundaries, so the system page is
* broken into EFI pages, and then each of them is verified.
*/
static int
ia64_verify_paddr(uint64_t paddr)
{
int i, j, cnt, found, desc_count, desc_size;
struct efi_memory_desc_t *desc;
struct machine_specific *ms;
uint64_t phys_end;
char *map;
int efi_pages;
ulong efi_pagesize;
/*
* When kernel text and data are mapped in region 5,
* and we're using the crash memory device driver,
* then the driver will gracefully fail the read attempt
* if the address is bogus.
*/
if ((VADDR_REGION(paddr) == KERNEL_VMALLOC_REGION) &&
(pc->flags & MEMMOD))
return TRUE;
ms = &ia64_machine_specific;
if (ms->ia64_memmap == NULL)
return TRUE;
desc_count = ms->efi_memmap_size/ms->efi_memdesc_size;
desc_size = ms->efi_memdesc_size;
efi_pagesize = (1 << EFI_PAGE_SHIFT);
efi_pages = PAGESIZE() / efi_pagesize;
paddr = PAGEBASE(paddr);
for (i = cnt = 0; i < efi_pages; i++, paddr += efi_pagesize) {
map = ms->ia64_memmap;
for (j = found = 0; j < desc_count; j++) {
desc = (struct efi_memory_desc_t *)map;
if (ia64_available_memory(desc)) {
phys_end = desc->phys_addr +
(desc->num_pages * efi_pagesize);
if ((paddr >= desc->phys_addr) &&
((paddr + efi_pagesize) <= phys_end)) {
cnt++;
found = TRUE;
}
}
if (found)
break;
map += desc_size;
}
}
return (cnt == efi_pages);
}
/*
* Check whether a "mem=X" argument was entered on the boot command line.
* Note that the default setting of the kernel mem_limit is ~0UL.
*/
static ulong
check_mem_limit(void)
{
ulong mem_limit;
char *saved_command_line, *p1, *p2;
int len;
if (!symbol_exists("mem_limit"))
return 0;
get_symbol_data("mem_limit", sizeof(ulong), &mem_limit);
if (mem_limit == ~0UL)
return 0;
mem_limit += 1;
if (!symbol_exists("saved_command_line"))
goto no_command_line;
len = get_array_length("saved_command_line", 0, sizeof(char));
if (!len)
goto no_command_line;
saved_command_line = GETBUF(len+1);
if (!readmem(symbol_value("saved_command_line"), KVADDR,
saved_command_line, len, "saved_command_line", RETURN_ON_ERROR))
goto no_command_line;
if (!(p1 = strstr(saved_command_line, "mem=")))
goto no_command_line;
p2 = p1;
while (*p2 && !whitespace(*p2))
p2++;
*p2 = NULLCHAR;
error(pc->flags & RUNTIME ? INFO : WARNING,
"boot command line argument: %s\n", p1);
return mem_limit;
no_command_line:
error(pc->flags & RUNTIME ? INFO : WARNING,
"boot command line memory limit: %lx\n", mem_limit);
return mem_limit;
}
#ifndef _ASM_IA64_UNWIND_H
#define _ASM_IA64_UNWIND_H
/*
* Copyright (C) 1999-2000 Hewlett-Packard Co
* Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
*
* A simple API for unwinding kernel stacks. This is used for
* debugging and error reporting purposes. The kernel doesn't need
* full-blown stack unwinding with all the bells and whitles, so there
* is not much point in implementing the full IA-64 unwind API (though
* it would of course be possible to implement the kernel API on top
* of it).
*/
struct task_struct; /* forward declaration */
struct switch_stack; /* forward declaration */
enum unw_application_register {
UNW_AR_BSP,
UNW_AR_BSPSTORE,
UNW_AR_PFS,
UNW_AR_RNAT,
UNW_AR_UNAT,
UNW_AR_LC,
UNW_AR_EC,
UNW_AR_FPSR,
UNW_AR_RSC,
UNW_AR_CCV
};
/*
* The following declarations are private to the unwind
* implementation:
*/
struct unw_stack {
unsigned long limit;
unsigned long top;
};
#define UNW_FLAG_INTERRUPT_FRAME (1UL << 0)
/*
* No user of this module should every access this structure directly
* as it is subject to change. It is declared here solely so we can
* use automatic variables.
*/
struct unw_frame_info {
struct unw_stack regstk;
struct unw_stack memstk;
unsigned int flags;
short hint;
short prev_script;
unsigned long bsp;
unsigned long sp; /* stack pointer */
unsigned long psp; /* previous sp */
unsigned long ip; /* instruction pointer */
unsigned long pr_val; /* current predicates */
unsigned long *cfm;
struct task_struct *task;
struct switch_stack *sw;
/* preserved state: */
unsigned long *pbsp; /* previous bsp */
unsigned long *bspstore;
unsigned long *pfs;
unsigned long *rnat;
unsigned long *rp;
unsigned long *pri_unat;
unsigned long *unat;
unsigned long *pr;
unsigned long *lc;
unsigned long *fpsr;
struct unw_ireg {
unsigned long *loc;
struct unw_ireg_nat {
int type : 3; /* enum unw_nat_type */
signed int off; /* NaT word is at loc+nat.off */
} nat;
} r4, r5, r6, r7;
unsigned long *b1, *b2, *b3, *b4, *b5;
struct ia64_fpreg *f2, *f3, *f4, *f5, *fr[16];
};
#endif /* _ASM_UNWIND_H */
/*
* Perform any leftover pre-prompt machine-specific initialization tasks here.
*/
static void
ia64_post_init(void)
{
struct machine_specific *ms;
struct gnu_request req;
struct syment *sp;
ulong flag;
ms = &ia64_machine_specific;
if (symbol_exists("unw_init_frame_info")) {
machdep->flags |= NEW_UNWIND;
if (MEMBER_EXISTS("unw_frame_info", "pt")) {
if (MEMBER_EXISTS("pt_regs", "ar_csd")) {
machdep->flags |= NEW_UNW_V3;
ms->unwind_init = unwind_init_v3;
ms->unwind = unwind_v3;
ms->unwind_debug = unwind_debug_v3;
ms->dump_unwind_stats = dump_unwind_stats_v3;
} else {
machdep->flags |= NEW_UNW_V2;
ms->unwind_init = unwind_init_v2;
ms->unwind = unwind_v2;
ms->unwind_debug = unwind_debug_v2;
ms->dump_unwind_stats = dump_unwind_stats_v2;
}
} else {
machdep->flags |= NEW_UNW_V1;
ms->unwind_init = unwind_init_v1;
ms->unwind = unwind_v1;
ms->unwind_debug = unwind_debug_v1;
ms->dump_unwind_stats = dump_unwind_stats_v1;
}
} else {
machdep->flags |= OLD_UNWIND;
ms->unwind_init = ia64_old_unwind_init;
ms->unwind = ia64_old_unwind;
}
ms->unwind_init();
if (!VALID_STRUCT(cpuinfo_ia64))
error(WARNING, "cpuinfo_ia64 structure does not exist\n");
else {
if (symbol_exists("_cpu_data"))
ms->cpu_data_address = symbol_value("_cpu_data");
else if (symbol_exists("boot_cpu_data"))
get_symbol_data("boot_cpu_data", sizeof(ulong),
&ms->cpu_data_address);
else if (symbol_exists("cpu_data"))
ms->cpu_data_address = symbol_value("cpu_data");
else if ((sp = per_cpu_symbol_search("per_cpu__cpu_info")) ||
(sp = per_cpu_symbol_search("per_cpu__ia64_cpu_info"))) {
if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF))
ms->cpu_data_address = sp->value +
kt->__per_cpu_offset[0];
else
ms->cpu_data_address = sp->value;
} else {
error(WARNING, "cannot find cpuinfo_ia64 location\n");
ms->cpu_data_address = 0;
}
if (ms->cpu_data_address) {
if (VALID_MEMBER(cpuinfo_ia64_unimpl_va_mask))
readmem(ms->cpu_data_address +
OFFSET(cpuinfo_ia64_unimpl_va_mask),
KVADDR, &ms->unimpl_va_mask,
sizeof(ulong),
"unimpl_va_mask", FAULT_ON_ERROR);
if (VALID_MEMBER(cpuinfo_ia64_unimpl_pa_mask))
readmem(ms->cpu_data_address +
OFFSET(cpuinfo_ia64_unimpl_pa_mask),
KVADDR, &ms->unimpl_pa_mask,
sizeof(ulong),
"unimpl_pa_mask", FAULT_ON_ERROR);
}
}
if (symbol_exists("ia64_init_stack") && !ms->ia64_init_stack_size) {
get_symbol_type("ia64_init_stack", NULL, &req);
ms->ia64_init_stack_size = req.length;
}
if (DUMPFILE() && ia64_in_init_stack(SWITCH_STACK_ADDR(CURRENT_TASK())))
machdep->flags |= INIT;
if (DUMPFILE() && (flag = ia64_in_per_cpu_mca_stack()))
machdep->flags |= flag;
}
/*
* Try using the old unwind scheme if the new one fails,
* that is as long as the unw_frame_info structs are the
* same size.
*/
static void
try_old_unwind(struct bt_info *bt)
{
if ((machdep->flags & NEW_UNWIND) &&
(STRUCT_SIZE("unw_frame_info") == sizeof(struct unw_frame_info))) {
error(INFO, "unwind: trying old unwind mechanism\n");
ia64_old_unwind(bt);
}
}
/*
* Unwind the stack using the basic method used when CONFIG_IA64_NEW_UNWIND
* is not configured into the kernel.
*
* NOTE: see kernel source: show_stack() and/or kdba_bt_stack()
*/
static void
ia64_old_unwind_init(void)
{
long len;
len = STRUCT_SIZE("unw_frame_info");
if (len < 0) {
error(WARNING, "cannot determine size of unw_frame_info\n");
machdep->flags |= UNW_OUT_OF_SYNC;
} else if (len != sizeof(struct unw_frame_info)) {
error(WARNING, "unw_frame_info size differs: %ld (local: %d)\n",
len, sizeof(struct unw_frame_info));
machdep->flags |= UNW_OUT_OF_SYNC;
}
}
static int unw_debug; /* debug fprintf indent */
static void
ia64_old_unwind(struct bt_info *bt)
{
struct unw_frame_info unw_frame_info, *info;
struct syment *sm;
int frame;
char *name;
if (bt->debug)
CRASHDEBUG_SUSPEND(bt->debug);
if (CRASHDEBUG(1))
unw_debug = 0;
info = &unw_frame_info;
unw_init_from_blocked_task(info, bt->task);
frame = 0;
do {
if (info->ip == 0)
break;
if (!IS_KVADDR(info->ip))
break;
if ((sm = value_search(info->ip, NULL)))
name = sm->name;
else
name = "(unknown)";
if (BT_REFERENCE_CHECK(bt)) {
switch (bt->ref->cmdflags &
(BT_REF_SYMBOL|BT_REF_HEXVAL))
{
case BT_REF_SYMBOL:
if (STREQ(name, bt->ref->str)) {
bt->ref->cmdflags |= BT_REF_FOUND;
goto unwind_return;
}
break;
case BT_REF_HEXVAL:
if (bt->ref->hexval == info->ip) {
bt->ref->cmdflags |= BT_REF_FOUND;
goto unwind_return;
}
break;
}
} else {
fprintf(fp, "%s#%d [BSP:%lx] %s at %lx\n",
frame >= 10 ? "" : " ", frame,
info->bsp, name, info->ip);
if (bt->flags & BT_FULL)
rse_function_params(info, name);
if (bt->flags & BT_LINE_NUMBERS)
ia64_dump_line_number(info->ip);
}
frame++;
if (CRASHDEBUG(1))
unw_debug = 0;
if (STREQ(name, "start_kernel"))
break;
} while (old_unw_unwind(info) >= 0);
unwind_return:
if (!BT_REFERENCE_CHECK(bt) && !is_kernel_thread(bt->task))
ia64_exception_frame(bt->stacktop - SIZE(pt_regs), bt);
if (bt->debug)
CRASHDEBUG_RESTORE();
}
static unsigned long
ia64_rse_slot_num (unsigned long *addr)
{
return (((unsigned long) addr) >> 3) & 0x3f;
}
/*
* Given a bsp address and a number of register locations, calculate a new
* bsp address, accounting for any intervening RNAT stores.
*/
static unsigned long *
ia64_rse_skip_regs (unsigned long *addr, long num_regs)
{
long delta = ia64_rse_slot_num(addr) + num_regs;
if (CRASHDEBUG(1)) {
fprintf(fp,
"%sia64_rse_skip_regs: ia64_rse_slot_num(%lx): %ld num_regs: %ld\n",
space(unw_debug),
(ulong)addr, ia64_rse_slot_num(addr), num_regs);
}
if (num_regs < 0)
delta -= 0x3e;
if (CRASHDEBUG(1)) {
fprintf(fp, "%sia64_rse_skip_regs: delta: %ld return(%lx)",
space(unw_debug), delta,
(ulong)(addr + num_regs + delta/0x3f));
if (addr > (addr + num_regs + delta/0x3f))
fprintf(fp, "(-%ld)\n",
addr - (addr + num_regs + delta/0x3f));
else
fprintf(fp, "(+%ld)\n",
(addr + num_regs + delta/0x3f) - addr);
}
return(addr + num_regs + delta/0x3f);
}
/*
* Returns the address of the RNAT slot that covers the slot at
* address SLOT_ADDR.
*/
static unsigned long *
ia64_rse_rnat_addr (unsigned long *slot_addr)
{
return (unsigned long *) ((unsigned long) slot_addr | (0x3f << 3));
}
/*
* Initialize the key fields in the unw_frame_info structure.
*
* NOTE: see kernel source: unw_init_from_blocked_task()
*/
static void
unw_init_from_blocked_task(struct unw_frame_info *info, ulong task)
{
ulong sw;
ulong sol, limit, top;
ulong ar_pfs, ar_bspstore, b0;
sw = SWITCH_STACK_ADDR(task);
BZERO(info, sizeof(struct unw_frame_info));
readmem(sw + OFFSET(switch_stack_b0), KVADDR,
&b0, sizeof(ulong), "switch_stack b0", FAULT_ON_ERROR);
readmem(sw + OFFSET(switch_stack_ar_pfs), KVADDR,
&ar_pfs, sizeof(ulong), "switch_stack ar_pfs", FAULT_ON_ERROR);
readmem(sw + OFFSET(switch_stack_ar_bspstore), KVADDR,
&ar_bspstore, sizeof(ulong), "switch_stack ar_bspstore",
FAULT_ON_ERROR);
sol = (ar_pfs >> 7) & 0x7f; /* size of locals */
limit = task + IA64_RBS_OFFSET;
top = ar_bspstore;
if ((top - task) >= IA64_STK_OFFSET)
top = limit;
if (CRASHDEBUG(1)) {
unw_debug++;
fprintf(fp,
"unw_init_from_blocked_task: stack top: %lx sol: %ld\n",
top, sol);
}
info->regstk.limit = limit;
info->regstk.top = top;
info->sw = (struct switch_stack *)sw;
info->bsp = (ulong)ia64_rse_skip_regs((ulong *)info->regstk.top, -sol);
info->cfm = (ulong *)(sw + OFFSET(switch_stack_ar_pfs));
info->ip = b0;
if (CRASHDEBUG(1))
dump_unw_frame_info(info);
}
/*
* Update the unw_frame_info structure based upon its current state.
* This routine works without enabling CONFIG_IA64_NEW_UNWIND because
* gdb allocates two additional "local" register locations for each
* function, found at the end of the stored locals:
*
* register "sol-1" (last local) = ar.pfs (gives us previous sol)
* register "sol-2" (2nd to last local = b0 to previous address
*
* NOTE: see kernel source: unw_unwind() (#ifndef CONFIG_IA64_NEW_UNWIND)
* On entry, info->regstk.top should point to the register backing
* store for r32.
*/
static int
old_unw_unwind (struct unw_frame_info *info)
{
unsigned long sol, cfm;
int is_nat;
if (!readmem((ulong)info->cfm, KVADDR, &cfm,
sizeof(long), "info->cfm", QUIET|RETURN_ON_ERROR))
return -1;
sol = (cfm >> 7) & 0x7f; /* size of locals */
if (CRASHDEBUG(1)) {
fprintf(fp, "old_unw_unwind: cfm: %lx sol: %ld\n", cfm, sol);
unw_debug++;
}
/*
* In general, we would have to make use of unwind info to
* unwind an IA-64 stack, but for now gcc uses a special
* convention that makes this possible without full-fledged
* unwind info. Specifically, we expect "rp" in the second
* last, and "ar.pfs" in the last local register, so the
* number of locals in a frame must be at least two. If it's
* less than that, we reached the end of the C call stack.
*/
if (sol < 2)
return -1;
info->ip = rse_read_reg(info, sol - 2, &is_nat);
if (CRASHDEBUG(1))
fprintf(fp, "old_unw_unwind: ip: %lx\n", info->ip);
if (is_nat || (info->ip & (machdep->machspec->unimpl_va_mask | 0xf)))
return -1;
info->cfm = ia64_rse_skip_regs((ulong *)info->bsp, sol - 1);
cfm = rse_read_reg(info, sol - 1, &is_nat);
if (CRASHDEBUG(1))
fprintf(fp, "old_unw_unwind: info->cfm: %lx => %lx\n",
(ulong)info->cfm, cfm);
if (is_nat)
return -1;
sol = (cfm >> 7) & 0x7f;
info->bsp = (ulong)ia64_rse_skip_regs((ulong *)info->bsp, -sol);
if (CRASHDEBUG(1)) {
fprintf(fp, "old_unw_unwind: next sol: %ld\n", sol);
fprintf(fp, "old_unw_unwind: next bsp: %lx\n", info->bsp);
}
return 0;
#ifdef KERNEL_SOURCE
unsigned long sol, cfm = *info->cfm;
int is_nat;
sol = (cfm >> 7) & 0x7f; /* size of locals */
/*
* In general, we would have to make use of unwind info to
* unwind an IA-64 stack, but for now gcc uses a special
* convention that makes this possible without full-fledged
* unwind info. Specifically, we expect "rp" in the second
* last, and "ar.pfs" in the last local register, so the
* number of locals in a frame must be at least two. If it's
* less than that, we reached the end of the C call stack.
*/
if (sol < 2)
return -1;
info->ip = rse_read_reg(info, sol - 2, &is_nat);
if (is_nat || (info->ip & (my_cpu_data.unimpl_va_mask | 0xf)))
/* reject let obviously bad addresses */
return -1;
info->cfm = ia64_rse_skip_regs((unsigned long *) info->bsp, sol - 1);
cfm = rse_read_reg(info, sol - 1, &is_nat);
if (is_nat)
return -1;
sol = (cfm >> 7) & 0x7f;
info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->bsp, -sol);
return 0;
#endif /* KERNEL_SOURCE */
}
/*
* Retrieve a register value from the stack, returning its NAT attribute
* as well.
*
* NOTE: see kernel source: read_reg()
*/
static ulong
rse_read_reg (struct unw_frame_info *info, int regnum, int *is_nat)
{
ulong *addr, *rnat_addr, rnat;
ulong regcontent;
if (CRASHDEBUG(1)) {
fprintf(fp, "%srse_read_reg: bsp: %lx\n", space(unw_debug),
info->bsp);
unw_debug++;
}
addr = ia64_rse_skip_regs((unsigned long *) info->bsp, regnum);
if (CRASHDEBUG(1)) {
unw_debug--;
fprintf(fp, "%srse_read_reg: addr: %lx\n",
space(unw_debug), (ulong)addr);
}
if (((ulong)addr < info->regstk.limit) ||
((ulong)addr >= info->regstk.top) ||
(((long)addr & 0x7) != 0)) {
*is_nat = 1;
if (CRASHDEBUG(1))
fprintf(fp,
"%srse_read_reg: is_nat: %d -- return 0xdeadbeefdeadbeef\n",
space(unw_debug), *is_nat);
return 0xdeadbeefdeadbeef;
}
rnat_addr = ia64_rse_rnat_addr(addr);
if (CRASHDEBUG(1))
fprintf(fp, "%srse_read_reg: rnat_addr: %lx\n",
space(unw_debug), (ulong)rnat_addr);
if ((unsigned long) rnat_addr >= info->regstk.top)
readmem((ulong)(info->sw) + OFFSET(switch_stack_ar_rnat),
KVADDR, &rnat, sizeof(long),
"info->sw->ar_rnat", FAULT_ON_ERROR);
else
readmem((ulong)rnat_addr, KVADDR, &rnat, sizeof(long),
"rnat_addr", FAULT_ON_ERROR);
*is_nat = (rnat & (1UL << ia64_rse_slot_num(addr))) != 0;
if (CRASHDEBUG(1))
fprintf(fp, "%srse_read_reg: rnat: %lx is_nat: %d\n",
space(unw_debug), rnat, *is_nat);
readmem((ulong)addr, KVADDR, &regcontent, sizeof(long),
"rse_read_reg addr", FAULT_ON_ERROR);
if (CRASHDEBUG(1)) {
char buf[BUFSIZE];
fprintf(fp, "%srse_read_reg: addr: %lx => %lx ",
space(unw_debug), (ulong)addr, regcontent);
if (is_kernel_text(regcontent))
fprintf(fp, "(%s)",
value_to_symstr(regcontent, buf, pc->output_radix));
fprintf(fp, "\n");
}
return regcontent;
}
/*
* Display the arguments to a function, presuming that they are found at
* the beginning of the sol section.
*/
#define MAX_REGISTER_PARAMS (8)
static void
rse_function_params(struct unw_frame_info *info, char *name)
{
int i;
int numargs, is_nat[MAX_REGISTER_PARAMS];
char buf1[BUFSIZE], buf2[BUFSIZE], *p1, *p2;
ulong arglist[MAX_REGISTER_PARAMS];
numargs = MIN(get_function_numargs(info->ip), MAX_REGISTER_PARAMS);
if (CRASHDEBUG(1))
fprintf(fp, "rse_function_params: %s: %d args\n",
name, numargs);
switch (numargs)
{
case 0:
fprintf(fp, " (void)\n");
return;
case -1:
return;
default:
break;
}
for (i = 0; i < numargs; i++)
arglist[i] = rse_read_reg(info, i, &is_nat[i]);
sprintf(buf1, " (");
for (i = 0; i < numargs; i++) {
p1 = &buf1[strlen(buf1)];
if (is_nat[i])
sprintf(buf2, "[NAT]");
else {
if ((p2 = value_symbol(arglist[i])))
sprintf(buf2, "%s", p2);
else
sprintf(buf2, "%lx", arglist[i]);
}
sprintf(p1, "%s%s", i ? ", " : "", buf2);
if (strlen(buf1) >= 80)
sprintf(p1, ",\n %s", buf2);
}
strcat(buf1, ")\n");
fprintf(fp, "%s", buf1);
}
static void
dump_unw_frame_info(struct unw_frame_info *info)
{
unw_debug++;
fprintf(fp, "%sregstk.limit: %lx\n",
space(unw_debug), info->regstk.limit);
fprintf(fp, "%s regstk.top: %lx\n",
space(unw_debug), info->regstk.top);
fprintf(fp, "%s sw: %lx\n",
space(unw_debug), (ulong)info->sw);
fprintf(fp, "%s bsp: %lx\n",
space(unw_debug), info->bsp);
fprintf(fp, "%s cfm: %lx\n",
space(unw_debug), (ulong)info->cfm);
fprintf(fp, "%s ip: %lx\n",
space(unw_debug), info->ip);
unw_debug--;
}
static const char *hook_files[] = {
"arch/ia64/kernel/entry.S",
"arch/ia64/kernel/head.S",
};
#define ENTRY_S ((char **)&hook_files[0])
#define HEAD_S ((char **)&hook_files[1])
static struct line_number_hook ia64_line_number_hooks[] = {
{"ia64_execve", ENTRY_S},
{"sys_clone2", ENTRY_S},
{"sys_clone", ENTRY_S},
{"ia64_switch_to", ENTRY_S},
{"save_switch_stack", ENTRY_S},
{"load_switch_stack", ENTRY_S},
{"__ia64_syscall", ENTRY_S},
{"invoke_syscall_trace", ENTRY_S},
{"ia64_trace_syscall", ENTRY_S},
{"ia64_ret_from_clone", ENTRY_S},
{"ia64_ret_from_syscall", ENTRY_S},
{"ia64_leave_kernel", ENTRY_S},
{"handle_syscall_error", ENTRY_S},
{"invoke_schedule_tail", ENTRY_S},
{"invoke_schedule", ENTRY_S},
{"handle_signal_delivery", ENTRY_S},
{"sys_rt_sigsuspend", ENTRY_S},
{"sys_rt_sigreturn", ENTRY_S},
{"ia64_prepare_handle_unaligned", ENTRY_S},
{"unw_init_running", ENTRY_S},
{"_start", HEAD_S},
{"ia64_save_debug_regs", HEAD_S},
{"ia64_load_debug_regs", HEAD_S},
{"__ia64_save_fpu", HEAD_S},
{"__ia64_load_fpu", HEAD_S},
{"__ia64_init_fpu", HEAD_S},
{"ia64_switch_mode", HEAD_S},
{"ia64_set_b1", HEAD_S},
{"ia64_set_b2", HEAD_S},
{"ia64_set_b3", HEAD_S},
{"ia64_set_b4", HEAD_S},
{"ia64_set_b5", HEAD_S},
{"ia64_spinlock_contention", HEAD_S},
{NULL, NULL} /* list must be NULL-terminated */
};
void
ia64_dump_line_number(ulong ip)
{
int retries;
char buf[BUFSIZE], *p;
retries = 0;
try_closest:
get_line_number(ip, buf, FALSE);
if (strlen(buf)) {
if (retries) {
p = strstr(buf, ": ");
if (p)
*p = NULLCHAR;
}
fprintf(fp, " %s\n", buf);
} else {
if (retries)
fprintf(fp, GDB_PATCHED() ?
"" : " (cannot determine file and line number)\n");
else {
retries++;
ip = closest_symbol_value(ip);
goto try_closest;
}
}
}
/*
* For now, just make it a region 7 address for all cases, ignoring the
* fact that it might be in a 2.6 kernel's non-unity mapped region. XXX
*/
ulong
ia64_PTOV(ulong paddr)
{
ulong vaddr;
switch (machdep->machspec->kernel_region)
{
case KERNEL_VMALLOC_REGION:
// error(FATAL, "ia64_PTOV: TBD for kernels loaded in region 5\n");
default:
case KERNEL_CACHED_REGION:
vaddr = paddr + (ulong)(KERNEL_CACHED_BASE);
}
return vaddr;
}
/*
* Account for 2.6 kernel mapping in region 5.
*/
ulong
ia64_VTOP(ulong vaddr)
{
struct machine_specific *ms;
ulong paddr;
ms = &ia64_machine_specific;
switch (VADDR_REGION(vaddr))
{
case KERNEL_CACHED_REGION:
paddr = vaddr - (ulong)(KERNEL_CACHED_BASE);
break;
case KERNEL_UNCACHED_REGION:
paddr = vaddr - (ulong)(KERNEL_UNCACHED_BASE);
break;
/*
* Differentiate between a 2.6 kernel address in region 5 and
* a real vmalloc() address.
*/
case KERNEL_VMALLOC_REGION:
/*
* Real vmalloc() addresses should never be the subject
* of a VTOP() translation.
*/
if (ia64_IS_VMALLOC_ADDR(vaddr) ||
(ms->kernel_region != KERNEL_VMALLOC_REGION))
return(error(FATAL,
"ia64_VTOP(%lx): unexpected region 5 address\n",
vaddr));
/*
* If it's a region 5 kernel address, subtract the starting
* kernel virtual address, and then add the base physical page.
*/
paddr = vaddr - ms->kernel_start +
(ms->phys_start & KERNEL_TR_PAGE_MASK);
break;
default:
return(error(FATAL,
"ia64_VTOP(%lx): invalid kernel address\n", vaddr));
}
return paddr;
}
/*
* vmalloc() starting address is either the traditional 0xa000000000000000 or
* bumped up in 2.6 to 0xa000000200000000.
*/
int
ia64_IS_VMALLOC_ADDR(ulong vaddr)
{
return ((vaddr >= machdep->machspec->vmalloc_start) &&
(vaddr < (ulong)KERNEL_UNCACHED_BASE));
}
static int
compare_kvaddr(const void *v1, const void *v2)
{
struct vaddr_range *r1, *r2;
r1 = (struct vaddr_range *)v1;
r2 = (struct vaddr_range *)v2;
return (r1->start < r2->start ? -1 :
r1->start == r2->start ? 0 : 1);
}
static int
ia64_get_kvaddr_ranges(struct vaddr_range *vrp)
{
int cnt;
cnt = 0;
vrp[cnt].type = KVADDR_UNITY_MAP;
vrp[cnt].start = machdep->identity_map_base;
vrp[cnt++].end = vt->high_memory;
if (machdep->machspec->kernel_start != machdep->identity_map_base) {
vrp[cnt].type = KVADDR_START_MAP;
vrp[cnt].start = machdep->machspec->kernel_start;
vrp[cnt++].end = kt->end;
}
vrp[cnt].type = KVADDR_VMALLOC;
vrp[cnt].start = machdep->machspec->vmalloc_start;
vrp[cnt++].end = (ulong)KERNEL_UNCACHED_REGION << REGION_SHIFT;
if (VADDR_REGION(vt->node_table[0].mem_map) == KERNEL_VMALLOC_REGION) {
vrp[cnt].type = KVADDR_VMEMMAP;
vrp[cnt].start = vt->node_table[0].mem_map;
vrp[cnt].end = vt->node_table[vt->numnodes-1].mem_map +
(vt->node_table[vt->numnodes-1].size *
SIZE(page));
/*
* Prevent overlap with KVADDR_VMALLOC range.
*/
if (vrp[cnt].start > vrp[cnt-1].start)
vrp[cnt-1].end = vrp[cnt].start;
cnt++;
}
qsort(vrp, cnt, sizeof(struct vaddr_range), compare_kvaddr);
return cnt;
}
/* Generic abstraction to translate user or kernel virtual
* addresses to physical using a 4 level page table.
*/
static int
ia64_vtop_4l_xen_wpt(ulong vaddr, physaddr_t *paddr, ulong *pgd, int verbose, int usr)
{
error(FATAL, "ia64_vtop_4l_xen_wpt: TBD\n");
return FALSE;
#ifdef TBD
ulong *page_dir;
ulong *page_upper;
ulong *page_middle;
ulong *page_table;
ulong pgd_pte;
ulong pud_pte;
ulong pmd_pte;
ulong pte;
ulong region, offset;
if (usr) {
region = VADDR_REGION(vaddr);
offset = (vaddr >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1);
offset |= (region << (PAGESHIFT() - 6));
page_dir = pgd + offset;
} else {
if (!(pgd = (ulong *)vt->kernel_pgd[0]))
error(FATAL, "cannot determine kernel pgd pointer\n");
page_dir = pgd + ((vaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1));
}
if (verbose)
fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));
if (verbose)
fprintf(fp, " PGD: %lx => %lx\n", (ulong)page_dir, pgd_pte);
if (!(pgd_pte))
return FALSE;
offset = (vaddr >> PUD_SHIFT) & (PTRS_PER_PUD - 1);
page_upper = (ulong *)(PTOV(pgd_pte & _PFN_MASK)) + offset;
FILL_PUD(PAGEBASE(page_upper), KVADDR, PAGESIZE());
pud_pte = ULONG(machdep->pud + PAGEOFFSET(page_upper));
if (verbose)
fprintf(fp, " PUD: %lx => %lx\n", (ulong)page_upper, pud_pte);
if (!(pud_pte))
return FALSE;
offset = (vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
page_middle = (ulong *)(PTOV(pud_pte & _PFN_MASK)) + offset;
FILL_PMD(PAGEBASE(page_middle), KVADDR, PAGESIZE());
pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));
if (verbose)
fprintf(fp, " PMD: %lx => %lx\n", (ulong)page_middle, pmd_pte);
if (!(pmd_pte))
return FALSE;
offset = (vaddr >> PAGESHIFT()) & (PTRS_PER_PTE - 1);
page_table = (ulong *)(PTOV(pmd_pte & _PFN_MASK)) + offset;
FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE());
pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
if (verbose)
fprintf(fp, " PTE: %lx => %lx\n", (ulong)page_table, pte);
if (!(pte & (_PAGE_P))) {
if (usr)
*paddr = pte;
if (pte && verbose) {
fprintf(fp, "\n");
ia64_translate_pte(pte, 0, 0);
}
return FALSE;
}
*paddr = (pte & _PFN_MASK) + PAGEOFFSET(vaddr);
if (verbose) {
fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr));
ia64_translate_pte(pte, 0, 0);
}
return TRUE;
#endif
}
/* Generic abstraction to translate user or kernel virtual
* addresses to physical using a 3 level page table.
*/
static int
ia64_vtop_xen_wpt(ulong vaddr, physaddr_t *paddr, ulong *pgd, int verbose, int usr)
{
error(FATAL, "ia64_vtop_xen_wpt: TBD\n");
return FALSE;
#ifdef TBD
ulong *page_dir;
ulong *page_middle;
ulong *page_table;
ulong pgd_pte;
ulong pmd_pte;
ulong pte;
ulong region, offset;
if (usr) {
region = VADDR_REGION(vaddr);
offset = (vaddr >> PGDIR_SHIFT) & ((PTRS_PER_PGD >> 3) - 1);
offset |= (region << (PAGESHIFT() - 6));
page_dir = pgd + offset;
} else {
if (!(pgd = (ulong *)vt->kernel_pgd[0]))
error(FATAL, "cannot determine kernel pgd pointer\n");
page_dir = pgd + ((vaddr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1));
}
if (verbose)
fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));
if (verbose)
fprintf(fp, " PGD: %lx => %lx\n", (ulong)page_dir, pgd_pte);
if (!(pgd_pte))
return FALSE;
offset = (vaddr >> PMD_SHIFT) & (PTRS_PER_PMD - 1);
page_middle = (ulong *)(PTOV(pgd_pte & _PFN_MASK)) + offset;
FILL_PMD(PAGEBASE(page_middle), KVADDR, PAGESIZE());
pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));
if (verbose)
fprintf(fp, " PMD: %lx => %lx\n", (ulong)page_middle, pmd_pte);
if (!(pmd_pte))
return FALSE;
offset = (vaddr >> PAGESHIFT()) & (PTRS_PER_PTE - 1);
page_table = (ulong *)(PTOV(pmd_pte & _PFN_MASK)) + offset;
FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE());
pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
if (verbose)
fprintf(fp, " PTE: %lx => %lx\n", (ulong)page_table, pte);
if (!(pte & (_PAGE_P))) {
if (usr)
*paddr = pte;
if (pte && verbose) {
fprintf(fp, "\n");
ia64_translate_pte(pte, 0, 0);
}
return FALSE;
}
*paddr = (pte & _PFN_MASK) + PAGEOFFSET(vaddr);
if (verbose) {
fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr));
ia64_translate_pte(pte, 0, 0);
}
return TRUE;
#endif
}
#include "netdump.h"
#include "xen_dom0.h"
/*
* Determine the relocatable physical address base.
*/
static void
ia64_calc_phys_start(void)
{
FILE *iomem;
int i, found, errflag;
char buf[BUFSIZE];
char *p1;
ulong kernel_code_start;
struct vmcore_data *vd;
ulong phys_start, text_start;
Elf64_Phdr *phdr = NULL;
/*
* Default to 64MB.
*/
machdep->machspec->phys_start = DEFAULT_PHYS_START;
text_start = symbol_exists("_text") ? symbol_value("_text") : BADADDR;
if (ACTIVE()) {
if ((iomem = fopen("/proc/iomem", "r")) == NULL)
return;
errflag = 1;
while (fgets(buf, BUFSIZE, iomem)) {
if (strstr(buf, ": Kernel code")) {
clean_line(buf);
errflag = 0;
break;
}
}
fclose(iomem);
if (errflag)
return;
if (!(p1 = strstr(buf, "-")))
return;
else
*p1 = NULLCHAR;
errflag = 0;
kernel_code_start = htol(buf, RETURN_ON_ERROR|QUIET, &errflag);
if (errflag)
return;
machdep->machspec->phys_start = kernel_code_start;
if (CRASHDEBUG(1)) {
if (text_start == BADADDR)
fprintf(fp, "_text: (unknown) ");
else
fprintf(fp, "_text: %lx ", text_start);
fprintf(fp, "Kernel code: %lx -> ", kernel_code_start);
fprintf(fp, "phys_start: %lx\n\n",
machdep->machspec->phys_start);
}
return;
}
/*
* Get relocation value from whatever dumpfile format is being used.
*/
if (DISKDUMP_DUMPFILE()) {
if (diskdump_phys_base(&phys_start)) {
machdep->machspec->phys_start = phys_start;
if (CRASHDEBUG(1))
fprintf(fp,
"compressed kdump: phys_start: %lx\n",
phys_start);
}
return;
} else if (LKCD_DUMPFILE()) {
if (lkcd_get_kernel_start(&phys_start)) {
machdep->machspec->phys_start = phys_start;
if (CRASHDEBUG(1))
fprintf(fp,
"LKCD dump: phys_start: %lx\n",
phys_start);
}
}
if ((vd = get_kdump_vmcore_data())) {
/*
* There should be at most one region 5 region, and it
* should be equal to "_text". If not, take whatever
* region 5 address comes first and hope for the best.
*/
for (i = found = 0; i < vd->num_pt_load_segments; i++) {
phdr = vd->load64 + i;
if (phdr->p_vaddr == text_start) {
machdep->machspec->phys_start = phdr->p_paddr;
found++;
break;
}
}
for (i = 0; !found && (i < vd->num_pt_load_segments); i++) {
phdr = vd->load64 + i;
if (VADDR_REGION(phdr->p_vaddr) == KERNEL_VMALLOC_REGION) {
machdep->machspec->phys_start = phdr->p_paddr;
found++;
break;
}
}
if (found && CRASHDEBUG(1)) {
if (text_start == BADADDR)
fprintf(fp, "_text: (unknown) ");
else
fprintf(fp, "_text: %lx ", text_start);
fprintf(fp, "p_vaddr: %lx p_paddr: %lx\n",
phdr->p_vaddr, phdr->p_paddr);
}
return;
}
}
/*
* From the xen vmcore, create an index of mfns for each page that makes
* up the dom0 kernel's complete phys_to_machine_mapping[max_pfn] array.
*/
static int
ia64_xen_kdump_p2m_create(struct xen_kdump_data *xkd)
{
/*
* Temporarily read physical (machine) addresses from vmcore.
*/
pc->curcmd_flags |= XEN_MACHINE_ADDR;
if (CRASHDEBUG(1)) {
fprintf(fp, "readmem (temporary): force XEN_MACHINE_ADDR\n");
fprintf(fp, "ia64_xen_kdump_p2m_create: p2m_mfn: %lx\n", xkd->p2m_mfn);
}
if ((xkd->p2m_mfn_frame_list = (ulong *)malloc(PAGESIZE())) == NULL)
error(FATAL, "cannot malloc p2m_frame_list");
if (!readmem(PTOB(xkd->p2m_mfn), PHYSADDR, xkd->p2m_mfn_frame_list, PAGESIZE(),
"xen kdump p2m mfn page", RETURN_ON_ERROR))
error(FATAL, "cannot read xen kdump p2m mfn page\n");
xkd->p2m_frames = PAGESIZE()/sizeof(ulong);
pc->curcmd_flags &= ~XEN_MACHINE_ADDR;
if (CRASHDEBUG(1))
fprintf(fp, "readmem (restore): p2m translation\n");
return TRUE;
}
physaddr_t
ia64_xen_kdump_p2m(struct xen_kdump_data *xkd, physaddr_t pseudo)
{
ulong pgd_idx, pte_idx;
ulong pmd, pte;
physaddr_t paddr;
/*
* Temporarily read physical (machine) addresses from vmcore.
*/
pc->curcmd_flags |= XEN_MACHINE_ADDR;
if (CRASHDEBUG(1))
fprintf(fp, "readmem (temporary): force XEN_MACHINE_ADDR\n");
xkd->accesses += 2;
pgd_idx = (pseudo >> PGDIR_SHIFT_3L) & (PTRS_PER_PGD - 1);
pmd = xkd->p2m_mfn_frame_list[pgd_idx] & _PFN_MASK;
if (!pmd) {
paddr = P2M_FAILURE;
goto out;
}
pmd += ((pseudo >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) * sizeof(ulong);
if (pmd != xkd->last_pmd_read) {
if (!readmem(pmd, PHYSADDR, &pte, sizeof(ulong),
"ia64_xen_kdump_p2m pmd", RETURN_ON_ERROR)) {
xkd->last_pmd_read = BADADDR;
xkd->last_mfn_read = BADADDR;
paddr = P2M_FAILURE;
goto out;
}
xkd->last_pmd_read = pmd;
} else {
pte = xkd->last_mfn_read;
xkd->cache_hits++;
}
pte = pte & _PFN_MASK;
if (!pte) {
paddr = P2M_FAILURE;
goto out;
}
if (pte != xkd->last_mfn_read) {
if (!readmem(pte, PHYSADDR, xkd->page, PAGESIZE(),
"ia64_xen_kdump_p2m pte page", RETURN_ON_ERROR)) {
xkd->last_pmd_read = BADADDR;
xkd->last_mfn_read = BADADDR;
paddr = P2M_FAILURE;
goto out;
}
xkd->last_mfn_read = pte;
} else
xkd->cache_hits++;
pte_idx = (pseudo >> PAGESHIFT()) & (PTRS_PER_PTE - 1);
paddr = *(((ulong *)xkd->page) + pte_idx);
if (!(paddr & _PAGE_P)) {
paddr = P2M_FAILURE;
goto out;
}
paddr = (paddr & _PFN_MASK) | PAGEOFFSET(pseudo);
out:
pc->curcmd_flags &= ~XEN_MACHINE_ADDR;
if (CRASHDEBUG(1))
fprintf(fp, "readmem (restore): p2m translation\n");
return paddr;
}
#include "xendump.h"
/*
* Create an index of mfns for each page that makes up the
* kernel's complete phys_to_machine_mapping[max_pfn] array.
*/
static int
ia64_xendump_p2m_create(struct xendump_data *xd)
{
if (!symbol_exists("phys_to_machine_mapping")) {
xd->flags |= XC_CORE_NO_P2M;
return TRUE;
}
error(FATAL, "ia64_xendump_p2m_create: TBD\n");
/* dummy calls for clean "make [wW]arn" */
ia64_debug_dump_page(NULL, NULL, NULL);
ia64_xendump_load_page(0, xd);
ia64_xendump_page_index(0, xd);
ia64_xendump_panic_task(xd); /* externally called */
ia64_get_xendump_regs(xd, NULL, NULL, NULL); /* externally called */
return FALSE;
}
static void
ia64_debug_dump_page(FILE *ofp, char *page, char *name)
{
int i;
ulong *up;
fprintf(ofp, "%s\n", name);
up = (ulong *)page;
for (i = 0; i < 1024; i++) {
fprintf(ofp, "%016lx: %016lx %016lx\n",
(ulong)((i * 2) * sizeof(ulong)),
*up, *(up+1));
up += 2;
}
}
/*
* Find the page associate with the kvaddr, and read its contents
* into the passed-in buffer.
*/
static char *
ia64_xendump_load_page(ulong kvaddr, struct xendump_data *xd)
{
error(FATAL, "ia64_xendump_load_page: TBD\n");
return NULL;
}
/*
* Find the dumpfile page index associated with the kvaddr.
*/
static int
ia64_xendump_page_index(ulong kvaddr, struct xendump_data *xd)
{
error(FATAL, "ia64_xendump_page_index: TBD\n");
return 0;
}
static ulong
ia64_xendump_panic_task(struct xendump_data *xd)
{
if (CRASHDEBUG(1))
error(INFO, "ia64_xendump_panic_task: TBD\n");
return NO_TASK;
}
static void
ia64_get_xendump_regs(struct xendump_data *xd, struct bt_info *bt, ulong *rip, ulong *rsp)
{
machdep->get_stack_frame(bt, rip, rsp);
if (is_task_active(bt->task) &&
!(bt->flags & (BT_TEXT_SYMBOLS_ALL|BT_TEXT_SYMBOLS)) &&
STREQ(closest_symbol(*rip), "schedule"))
error(INFO,
"xendump: switch_stack possibly not saved -- try \"bt -t\"\n");
}
/* for XEN Hypervisor analysis */
static int
ia64_is_kvaddr_hyper(ulong addr)
{
return (addr >= HYPERVISOR_VIRT_START && addr < HYPERVISOR_VIRT_END);
}
static int
ia64_kvtop_hyper(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose)
{
ulong virt_percpu_start, phys_percpu_start;
ulong addr, dirp, entry;
if (!IS_KVADDR(kvaddr))
return FALSE;
if (PERCPU_VIRT_ADDR(kvaddr)) {
virt_percpu_start = symbol_value("__phys_per_cpu_start");
phys_percpu_start = virt_percpu_start - DIRECTMAP_VIRT_START;
*paddr = kvaddr - PERCPU_ADDR + phys_percpu_start;
return TRUE;
} else if (DIRECTMAP_VIRT_ADDR(kvaddr)) {
*paddr = kvaddr - DIRECTMAP_VIRT_START;
return TRUE;
} else if (!FRAME_TABLE_VIRT_ADDR(kvaddr)) {
return FALSE;
}
/* frametable virtual address */
addr = kvaddr - xhmachdep->frame_table;
dirp = symbol_value("frametable_pg_dir");
dirp += ((addr >> PGDIR_SHIFT_3L) & (PTRS_PER_PGD - 1)) * sizeof(ulong);
readmem(dirp, KVADDR, &entry, sizeof(ulong),
"frametable_pg_dir", FAULT_ON_ERROR);
dirp = entry & _PFN_MASK;
if (!dirp)
return FALSE;
dirp += ((addr >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) * sizeof(ulong);
readmem(dirp, PHYSADDR, &entry, sizeof(ulong),
"frametable pmd", FAULT_ON_ERROR);
dirp = entry & _PFN_MASK;
if (!dirp)
return FALSE;
dirp += ((addr >> PAGESHIFT()) & (PTRS_PER_PTE - 1)) * sizeof(ulong);
readmem(dirp, PHYSADDR, &entry, sizeof(ulong),
"frametable pte", FAULT_ON_ERROR);
if (!(entry & _PAGE_P))
return FALSE;
*paddr = (entry & _PFN_MASK) + (kvaddr & (PAGESIZE() - 1));
return TRUE;
}
static void
ia64_post_init_hyper(void)
{
struct machine_specific *ms;
ulong frame_table;
ms = &ia64_machine_specific;
if (symbol_exists("unw_init_frame_info")) {
machdep->flags |= NEW_UNWIND;
if (MEMBER_EXISTS("unw_frame_info", "pt")) {
if (MEMBER_EXISTS("cpu_user_regs", "ar_csd")) {
machdep->flags |= NEW_UNW_V3;
ms->unwind_init = unwind_init_v3;
ms->unwind = unwind_v3;
ms->unwind_debug = unwind_debug_v3;
ms->dump_unwind_stats = dump_unwind_stats_v3;
} else {
machdep->flags |= NEW_UNW_V2;
ms->unwind_init = unwind_init_v2;
ms->unwind = unwind_v2;
ms->unwind_debug = unwind_debug_v2;
ms->dump_unwind_stats = dump_unwind_stats_v2;
}
} else {
machdep->flags |= NEW_UNW_V1;
ms->unwind_init = unwind_init_v1;
ms->unwind = unwind_v1;
ms->unwind_debug = unwind_debug_v1;
ms->dump_unwind_stats = dump_unwind_stats_v1;
}
} else {
machdep->flags |= OLD_UNWIND;
ms->unwind_init = ia64_old_unwind_init;
ms->unwind = ia64_old_unwind;
}
ms->unwind_init();
if (symbol_exists("frame_table")) {
frame_table = symbol_value("frame_table");
readmem(frame_table, KVADDR, &xhmachdep->frame_table, sizeof(ulong),
"frame_table virtual address", FAULT_ON_ERROR);
} else {
error(FATAL, "cannot find frame_table virtual address.");
}
}
int
ia64_in_mca_stack_hyper(ulong addr, struct bt_info *bt)
{
int plen, i;
ulong paddr, stackbase, stacktop;
ulong *__per_cpu_mca;
struct xen_hyper_vcpu_context *vcc;
vcc = xen_hyper_vcpu_to_vcpu_context(bt->task);
if (!vcc)
return 0;
if (!symbol_exists("__per_cpu_mca") ||
!(plen = get_array_length("__per_cpu_mca", NULL, 0)) ||
(plen < xht->pcpus))
return 0;
if (!machdep->kvtop(NULL, addr, &paddr, 0))
return 0;
__per_cpu_mca = (ulong *)GETBUF(sizeof(ulong) * plen);
if (!readmem(symbol_value("__per_cpu_mca"), KVADDR, __per_cpu_mca,
sizeof(ulong) * plen, "__per_cpu_mca", RETURN_ON_ERROR|QUIET))
return 0;
if (CRASHDEBUG(1)) {
for (i = 0; i < plen; i++) {
fprintf(fp, "__per_cpu_mca[%d]: %lx\n",
i, __per_cpu_mca[i]);
}
}
stackbase = __per_cpu_mca[vcc->processor];
stacktop = stackbase + (STACKSIZE() * 2);
FREEBUF(__per_cpu_mca);
if ((paddr >= stackbase) && (paddr < stacktop))
return 1;
else
return 0;
}
static void
ia64_init_hyper(int when)
{
struct syment *sp;
switch (when)
{
case SETUP_ENV:
#if defined(PR_SET_FPEMU) && defined(PR_FPEMU_NOPRINT)
prctl(PR_SET_FPEMU, PR_FPEMU_NOPRINT, 0, 0, 0);
#endif
#if defined(PR_SET_UNALIGN) && defined(PR_UNALIGN_NOPRINT)
prctl(PR_SET_UNALIGN, PR_UNALIGN_NOPRINT, 0, 0, 0);
#endif
break;
case PRE_SYMTAB:
machdep->verify_symbol = ia64_verify_symbol;
machdep->machspec = &ia64_machine_specific;
if (pc->flags & KERNEL_DEBUG_QUERY)
return;
machdep->pagesize = memory_page_size();
machdep->pageshift = ffs(machdep->pagesize) - 1;
machdep->pageoffset = machdep->pagesize - 1;
machdep->pagemask = ~(machdep->pageoffset);
switch (machdep->pagesize)
{
case 4096:
machdep->stacksize = (power(2, 3) * PAGESIZE());
break;
case 8192:
machdep->stacksize = (power(2, 2) * PAGESIZE());
break;
case 16384:
machdep->stacksize = (power(2, 1) * PAGESIZE());
break;
case 65536:
machdep->stacksize = (power(2, 0) * PAGESIZE());
break;
default:
machdep->stacksize = 32*1024;
break;
}
if ((machdep->pgd = (char *)malloc(PAGESIZE())) == NULL)
error(FATAL, "cannot malloc pgd space.");
if ((machdep->pud = (char *)malloc(PAGESIZE())) == NULL)
error(FATAL, "cannot malloc pud space.");
if ((machdep->pmd = (char *)malloc(PAGESIZE())) == NULL)
error(FATAL, "cannot malloc pmd space.");
if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL)
error(FATAL, "cannot malloc ptbl space.");
machdep->last_pgd_read = 0;
machdep->last_pud_read = 0;
machdep->last_pmd_read = 0;
machdep->last_ptbl_read = 0;
machdep->verify_paddr = ia64_verify_paddr;
machdep->ptrs_per_pgd = PTRS_PER_PGD;
machdep->machspec->phys_start = UNKNOWN_PHYS_START;
/* ODA: if need make hyper version
if (machdep->cmdline_args[0])
parse_cmdline_args(); */
break;
case PRE_GDB:
if (pc->flags & KERNEL_DEBUG_QUERY)
return;
machdep->kvbase = HYPERVISOR_VIRT_START;
machdep->identity_map_base = HYPERVISOR_VIRT_START;
machdep->is_kvaddr = ia64_is_kvaddr_hyper;
machdep->is_uvaddr = generic_is_uvaddr;
machdep->eframe_search = ia64_eframe_search;
machdep->back_trace = ia64_back_trace_cmd;
machdep->processor_speed = xen_hyper_ia64_processor_speed;
machdep->uvtop = ia64_uvtop;
machdep->kvtop = ia64_kvtop_hyper;
machdep->get_stack_frame = ia64_get_stack_frame;
machdep->get_stackbase = ia64_get_stackbase;
machdep->get_stacktop = ia64_get_stacktop;
machdep->translate_pte = ia64_translate_pte;
machdep->memory_size = xen_hyper_ia64_memory_size;
machdep->dis_filter = ia64_dis_filter;
machdep->cmd_mach = ia64_cmd_mach;
machdep->get_smp_cpus = xen_hyper_ia64_get_smp_cpus;
machdep->line_number_hooks = ia64_line_number_hooks;
machdep->value_to_symbol = generic_machdep_value_to_symbol;
machdep->init_kernel_pgd = NULL;
if ((sp = symbol_search("_stext"))) {
machdep->machspec->kernel_region =
VADDR_REGION(sp->value);
machdep->machspec->kernel_start = sp->value;
} else {
// machdep->machspec->kernel_region = KERNEL_CACHED_REGION;
// machdep->machspec->kernel_start = KERNEL_CACHED_BASE;
}
/* machdep table for Xen Hypervisor */
xhmachdep->pcpu_init = xen_hyper_ia64_pcpu_init;
break;
case POST_GDB:
STRUCT_SIZE_INIT(switch_stack, "switch_stack");
MEMBER_OFFSET_INIT(thread_struct_fph, "thread_struct", "fph");
MEMBER_OFFSET_INIT(switch_stack_b0, "switch_stack", "b0");
MEMBER_OFFSET_INIT(switch_stack_ar_bspstore,
"switch_stack", "ar_bspstore");
MEMBER_OFFSET_INIT(switch_stack_ar_pfs,
"switch_stack", "ar_pfs");
MEMBER_OFFSET_INIT(switch_stack_ar_rnat,
"switch_stack", "ar_rnat");
MEMBER_OFFSET_INIT(switch_stack_pr,
"switch_stack", "pr");
XEN_HYPER_STRUCT_SIZE_INIT(cpuinfo_ia64, "cpuinfo_ia64");
XEN_HYPER_MEMBER_OFFSET_INIT(cpuinfo_ia64_proc_freq, "cpuinfo_ia64", "proc_freq");
XEN_HYPER_MEMBER_OFFSET_INIT(cpuinfo_ia64_vendor, "cpuinfo_ia64", "vendor");
if (symbol_exists("per_cpu__cpu_info")) {
xht->cpu_data_address = symbol_value("per_cpu__cpu_info");
}
/* kakuma Can this be calculated? */
if (!machdep->hz) {
machdep->hz = XEN_HYPER_HZ;
}
break;
case POST_INIT:
ia64_post_init_hyper();
break;
}
}
#endif