/* 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
