mirror of https://github.com/crash-utility/crash
1254 lines
31 KiB
C
1254 lines
31 KiB
C
/* sparc64.c - core analysis suite
|
|
*
|
|
* Copyright (C) 2016 Oracle Corporation
|
|
*
|
|
* 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 SPARC64
|
|
|
|
#include "defs.h"
|
|
#include <stdio.h>
|
|
#include <elf.h>
|
|
#include <asm/ptrace.h>
|
|
#include <linux/const.h>
|
|
|
|
/* TT (Trap Type) is encoded into magic pt_regs field */
|
|
#define MAGIC_TT_MASK (0x1ff)
|
|
|
|
static const unsigned long not_valid_pte = ~0UL;
|
|
static struct machine_specific sparc64_machine_specific;
|
|
static unsigned long sparc64_ksp_offset;
|
|
|
|
static unsigned long
|
|
__va(unsigned long paddr)
|
|
{
|
|
return paddr + PAGE_OFFSET;
|
|
}
|
|
|
|
static unsigned long
|
|
__pa(unsigned long vaddr)
|
|
{
|
|
return vaddr - PAGE_OFFSET;
|
|
}
|
|
|
|
static void
|
|
sparc64_parse_cmdline_args(void)
|
|
{
|
|
}
|
|
|
|
/* This interface might not be required. */
|
|
static void
|
|
sparc64_clear_machdep_cache(void)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* "mach" command output.
|
|
*/
|
|
static void
|
|
sparc64_display_machine_stats(void)
|
|
{
|
|
int c;
|
|
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);
|
|
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: %ld\n", PAGE_SIZE);
|
|
fprintf(fp, " KERNEL VIRTUAL BASE: %lx\n", machdep->kvbase);
|
|
fprintf(fp, " KERNEL VMALLOC BASE: %lx\n", SPARC64_VMALLOC_START);
|
|
fprintf(fp, " KERNEL MODULES BASE: %lx\n", SPARC64_MODULES_VADDR);
|
|
fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE());
|
|
|
|
fprintf(fp, "HARD IRQ STACK SIZE: %ld\n", THREAD_SIZE);
|
|
fprintf(fp, " HARD IRQ STACKS:\n");
|
|
|
|
for (c = 0; c < kt->cpus; c++) {
|
|
if (!tt->hardirq_ctx[c])
|
|
continue;
|
|
sprintf(buf, "CPU %d", c);
|
|
fprintf(fp, "%19s: %lx\n", buf, tt->hardirq_ctx[c]);
|
|
}
|
|
|
|
fprintf(fp, "SOFT IRQ STACK SIZE: %ld\n", THREAD_SIZE);
|
|
fprintf(fp, " SOFT IRQ STACKS:\n");
|
|
for (c = 0; c < kt->cpus; c++) {
|
|
if (!tt->softirq_ctx[c])
|
|
continue;
|
|
sprintf(buf, "CPU %d", c);
|
|
fprintf(fp, "%19s: %lx\n", buf, tt->softirq_ctx[c]);
|
|
}
|
|
}
|
|
|
|
static void
|
|
sparc64_display_memmap(void)
|
|
{
|
|
unsigned long iomem_resource;
|
|
unsigned long resource;
|
|
unsigned long start, end, nameptr;
|
|
int size = STRUCT_SIZE("resource");
|
|
char *buf;
|
|
char name[32];
|
|
|
|
buf = GETBUF(size);
|
|
iomem_resource = symbol_value("iomem_resource");
|
|
|
|
readmem(iomem_resource + MEMBER_OFFSET("resource", "child"), KVADDR,
|
|
&resource, sizeof(resource), "iomem_resource", FAULT_ON_ERROR);
|
|
|
|
fprintf(fp, " PHYSICAL ADDRESS RANGE TYPE\n");
|
|
|
|
while (resource) {
|
|
readmem(resource, KVADDR, buf, size, "resource",
|
|
FAULT_ON_ERROR);
|
|
start = ULONG(buf + MEMBER_OFFSET("resource", "start"));
|
|
end = ULONG(buf + MEMBER_OFFSET("resource", "end"));
|
|
nameptr = ULONG(buf + MEMBER_OFFSET("resource", "name"));
|
|
|
|
readmem(nameptr, KVADDR, name, sizeof(name), "resource.name",
|
|
FAULT_ON_ERROR);
|
|
|
|
fprintf(fp, "%016lx - %016lx %-32s\n", start, end, name);
|
|
|
|
resource = ULONG(buf + MEMBER_OFFSET("resource", "sibling"));
|
|
}
|
|
FREEBUF(buf);
|
|
}
|
|
|
|
static void
|
|
sparc64_cmd_mach(void)
|
|
{
|
|
int c;
|
|
int mflag = 0;
|
|
|
|
while ((c = getopt(argcnt, args, "cdmx")) != EOF) {
|
|
switch (c) {
|
|
case 'm':
|
|
mflag++;
|
|
sparc64_display_memmap();
|
|
break;
|
|
case 'c':
|
|
fprintf(fp, "SPARC64: '-%c' option is not supported\n",
|
|
c);
|
|
return;
|
|
case 'd':
|
|
case 'x':
|
|
/* Just ignore these */
|
|
break;
|
|
default:
|
|
argerrs++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (argerrs)
|
|
cmd_usage(pc->curcmd, SYNOPSIS);
|
|
|
|
if (!mflag)
|
|
sparc64_display_machine_stats();
|
|
}
|
|
|
|
struct sparc64_mem_ranges {
|
|
unsigned long start;
|
|
unsigned long end;
|
|
};
|
|
|
|
#define NR_PHYS_RANGES (128)
|
|
static unsigned int nr_phys_ranges;
|
|
struct sparc64_mem_ranges phys_ranges[NR_PHYS_RANGES];
|
|
|
|
#define NR_IMAGE_RANGES (16)
|
|
static unsigned int nr_kimage_ranges;
|
|
struct sparc64_mem_ranges kimage_ranges[NR_IMAGE_RANGES];
|
|
|
|
/* There are three live cases:
|
|
* one) normal kernel
|
|
* two) --load-panic kernel
|
|
* and
|
|
* three) --load kernel
|
|
* One and two can be treated the same because the kernel is physically
|
|
* contiguous. Three isn't contiguous. The kernel is allocated in order
|
|
* nine allocation pages. We don't handle case three yet.
|
|
*/
|
|
|
|
static int
|
|
sparc64_phys_live_valid(unsigned long paddr)
|
|
{
|
|
unsigned int nr;
|
|
int rc = FALSE;
|
|
|
|
for (nr = 0; nr != nr_phys_ranges; nr++) {
|
|
if (paddr >= phys_ranges[nr].start &&
|
|
paddr < phys_ranges[nr].end) {
|
|
rc = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
sparc64_phys_kdump_valid(unsigned long paddr)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
sparc64_verify_paddr(unsigned long paddr)
|
|
{
|
|
int rc;
|
|
|
|
if (ACTIVE())
|
|
rc = sparc64_phys_live_valid(paddr);
|
|
else
|
|
rc = sparc64_phys_kdump_valid(paddr);
|
|
|
|
return rc;
|
|
}
|
|
|
|
static void
|
|
sparc6_phys_base_live_limits(void)
|
|
{
|
|
if (nr_phys_ranges >= NR_PHYS_RANGES)
|
|
error(FATAL, "sparc6_phys_base_live_limits: "
|
|
"NR_PHYS_RANGES exceeded.\n");
|
|
else if (nr_kimage_ranges >= NR_IMAGE_RANGES)
|
|
error(FATAL, "sparc6_phys_base_live_limits: "
|
|
"NR_IMAGE_RANGES exceeded.\n");
|
|
}
|
|
|
|
static void
|
|
sparc64_phys_base_live_valid(void)
|
|
{
|
|
if (!nr_phys_ranges)
|
|
error(FATAL, "No physical memory ranges.");
|
|
else if (!nr_kimage_ranges)
|
|
error(FATAL, "No vmlinux memory ranges.");
|
|
}
|
|
|
|
static void
|
|
sparc64_phys_base_live(void)
|
|
{
|
|
char line[BUFSIZE];
|
|
FILE *fp;
|
|
|
|
fp = fopen("/proc/iomem", "r");
|
|
if (fp == NULL)
|
|
error(FATAL, "Can't open /proc/iomem. We can't proceed.");
|
|
|
|
while (fgets(line, sizeof(line), fp) != 0) {
|
|
unsigned long start, end;
|
|
int count, consumed;
|
|
char *ch;
|
|
|
|
sparc6_phys_base_live_limits();
|
|
count = sscanf(line, "%lx-%lx : %n", &start, &end, &consumed);
|
|
if (count != 2)
|
|
continue;
|
|
ch = line + consumed;
|
|
if (memcmp(ch, "System RAM\n", 11) == 0) {
|
|
end = end + 1;
|
|
phys_ranges[nr_phys_ranges].start = start;
|
|
phys_ranges[nr_phys_ranges].end = end;
|
|
nr_phys_ranges++;
|
|
} else if ((memcmp(ch, "Kernel code\n", 12) == 0) ||
|
|
(memcmp(ch, "Kernel data\n", 12) == 0) ||
|
|
(memcmp(ch, "Kernel bss\n", 11) == 0)) {
|
|
kimage_ranges[nr_kimage_ranges].start = start;
|
|
kimage_ranges[nr_kimage_ranges].end = end;
|
|
nr_kimage_ranges++;
|
|
}
|
|
}
|
|
|
|
(void) fclose(fp);
|
|
sparc64_phys_base_live_valid();
|
|
}
|
|
|
|
static void
|
|
sparc64_phys_base_kdump(void)
|
|
{
|
|
}
|
|
|
|
static void
|
|
sparc64_phys_base(void)
|
|
{
|
|
if (ACTIVE())
|
|
return sparc64_phys_base_live();
|
|
else
|
|
return sparc64_phys_base_kdump();
|
|
}
|
|
|
|
static unsigned long kva_start, kva_end;
|
|
static unsigned long kpa_start, kpa_end;
|
|
|
|
static void
|
|
sparc64_kimage_limits_live(void)
|
|
{
|
|
kpa_start = kimage_ranges[0].start;
|
|
kpa_end = kpa_start + (kva_end - kva_start);
|
|
}
|
|
|
|
static void
|
|
sparc64_kimage_limits_kdump(void)
|
|
{
|
|
unsigned long phys_base;
|
|
|
|
if (DISKDUMP_DUMPFILE()) {
|
|
if (diskdump_phys_base(&phys_base)) {
|
|
kpa_start = phys_base | (kva_start & 0xffff);
|
|
kpa_end = kpa_start + (kva_end - kva_start);
|
|
return;
|
|
}
|
|
}
|
|
fprintf(stderr, "Can't determine phys_base\n");
|
|
}
|
|
|
|
static unsigned long
|
|
kimage_va_translate(unsigned long addr)
|
|
{
|
|
unsigned long paddr = (addr - kva_start) + kpa_start;
|
|
|
|
return paddr;
|
|
}
|
|
|
|
static int
|
|
kimage_va_range(unsigned long addr)
|
|
{
|
|
if (addr >= kva_start && addr < kva_end)
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
sparc64_kimage_limits(void)
|
|
{
|
|
kva_start = symbol_value("_stext");
|
|
kva_end = symbol_value("_end");
|
|
|
|
if (ACTIVE())
|
|
sparc64_kimage_limits_live();
|
|
else
|
|
sparc64_kimage_limits_kdump();
|
|
}
|
|
|
|
static int
|
|
sparc64_is_linear_mapped(unsigned long vaddr)
|
|
{
|
|
return (vaddr & PAGE_OFFSET) == PAGE_OFFSET;
|
|
}
|
|
|
|
static unsigned long
|
|
pte_to_pa(unsigned long pte)
|
|
{
|
|
unsigned long paddr = pte & _PAGE_PFN_MASK;
|
|
|
|
return paddr;
|
|
}
|
|
|
|
static unsigned long
|
|
fetch_page_table_level(unsigned long pte_kva, unsigned long vaddr,
|
|
unsigned int shift, unsigned int mask, const char *name,
|
|
int verbose)
|
|
{
|
|
unsigned int pte_index = (vaddr >> shift) & mask;
|
|
unsigned long page_table[PTES_PER_PAGE];
|
|
unsigned long pte = 0UL;
|
|
int rc;
|
|
|
|
rc = readmem(pte_kva, KVADDR, page_table, sizeof(page_table),
|
|
(char *)name, RETURN_ON_ERROR);
|
|
if (!rc)
|
|
goto out;
|
|
pte = page_table[pte_index];
|
|
if (verbose)
|
|
fprintf(fp,
|
|
"%s(0x%.16lx) fetch of pte @index[0x%.4x]=0x%.16lx\n",
|
|
name, pte_kva, pte_index, pte);
|
|
out:
|
|
return pte;
|
|
}
|
|
|
|
static unsigned long
|
|
pmd_is_huge(unsigned long pmd, unsigned long vaddr, int verbose)
|
|
{
|
|
unsigned long hpage_mask;
|
|
unsigned long paddr = 0UL;
|
|
|
|
if ((pmd & PAGE_PMD_HUGE) == 0UL)
|
|
goto out;
|
|
hpage_mask = ~((1UL << HPAGE_SHIFT) - 1UL);
|
|
paddr = pte_to_pa(pmd) + (vaddr & ~hpage_mask);
|
|
if (verbose)
|
|
fprintf(fp, "Huge Page/THP pmd=0x%.16lx paddr=0x%.16lx\n",
|
|
pmd, paddr);
|
|
out:
|
|
return paddr;
|
|
}
|
|
|
|
static unsigned long
|
|
sparc64_page_table_walk(unsigned long pgd, unsigned long vaddr, int verbose)
|
|
{
|
|
static const char *pgd_text = "pgd fetch";
|
|
static const char *pud_text = "pud fetch";
|
|
static const char *pmd_text = "pmd fetch";
|
|
static const char *pte_text = "pte fetch";
|
|
unsigned long kva = pgd;
|
|
unsigned long paddr;
|
|
unsigned long pte;
|
|
|
|
if (!sparc64_is_linear_mapped(kva))
|
|
error(FATAL,
|
|
"sparc64_page_table_walk: pgd must be identity mapped"
|
|
" but isn't (0xlx).", pgd);
|
|
|
|
pte = fetch_page_table_level(kva, vaddr, PGDIR_SHIFT,
|
|
PTES_PER_PAGE_MASK, pgd_text, verbose);
|
|
if (!pte)
|
|
goto bad;
|
|
kva = __va(pte);
|
|
|
|
pte = fetch_page_table_level(kva, vaddr, PUD_SHIFT, PTES_PER_PAGE_MASK,
|
|
pud_text, verbose);
|
|
if (!pte)
|
|
goto bad;
|
|
|
|
kva = __va(pte);
|
|
pte = fetch_page_table_level(kva, vaddr, PMD_SHIFT,
|
|
PTES_PER_PAGE_MASK, pmd_text, verbose);
|
|
if (!pte)
|
|
goto bad;
|
|
/* Check for a huge/THP page */
|
|
paddr = pmd_is_huge(pte, vaddr, verbose);
|
|
if (paddr)
|
|
goto out;
|
|
kva = __va(pte);
|
|
pte = fetch_page_table_level(kva, vaddr, PAGE_SHIFT,
|
|
PTRS_PER_PTE - 1, pte_text, verbose);
|
|
if ((pte & _PAGE_VALID) == 0UL)
|
|
goto bad;
|
|
paddr = pte_to_pa(pte);
|
|
paddr = paddr | (vaddr & ~PAGE_MASK);
|
|
out:
|
|
return paddr;
|
|
bad:
|
|
return not_valid_pte;
|
|
}
|
|
|
|
static void
|
|
sparc64_init_kernel_pgd(void)
|
|
{
|
|
int cpu, rc;
|
|
ulong v;
|
|
|
|
v = symbol_value("init_mm");
|
|
rc = readmem(v + OFFSET(mm_struct_pgd), KVADDR, &v, sizeof(v),
|
|
"init_mm.pgd", RETURN_ON_ERROR);
|
|
if (!rc) {
|
|
error(WARNING, "Can not determine pgd location.\n");
|
|
goto out;
|
|
}
|
|
|
|
for (cpu = 0; cpu < NR_CPUS; cpu++)
|
|
vt->kernel_pgd[cpu] = v;
|
|
out:
|
|
return;
|
|
}
|
|
|
|
static int
|
|
sparc64_get_smp_cpus(void)
|
|
{
|
|
int ncpu = MAX(get_cpus_online(), get_highest_cpu_online() + 1);
|
|
|
|
return ncpu;
|
|
}
|
|
|
|
static ulong
|
|
sparc64_vmalloc_start(void)
|
|
{
|
|
return SPARC64_VMALLOC_START;
|
|
}
|
|
|
|
int
|
|
sparc64_IS_VMALLOC_ADDR(ulong vaddr)
|
|
{
|
|
return (vaddr >= SPARC64_VMALLOC_START) &&
|
|
(vaddr < machdep->machspec->vmalloc_end);
|
|
}
|
|
|
|
static void
|
|
pt_clear_cache(void)
|
|
{
|
|
machdep->last_pgd_read = 0UL;
|
|
machdep->last_pud_read = 0UL;
|
|
machdep->last_pmd_read = 0UL;
|
|
machdep->last_ptbl_read = 0UL;
|
|
}
|
|
|
|
static void
|
|
pt_level_alloc(char **lvl, char *name)
|
|
{
|
|
size_t sz = PAGE_SIZE;
|
|
void *pointer = malloc(sz);
|
|
|
|
if (!pointer)
|
|
error(FATAL, name);
|
|
*lvl = pointer;
|
|
}
|
|
|
|
static int
|
|
sparc64_verify_symbol(const char *name, unsigned long value, char type)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
sparc64_verify_line_number(unsigned long pc, unsigned long low,
|
|
unsigned long high)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
static int
|
|
sparc64_dis_filter(ulong vaddr, char *inbuf, unsigned int radix)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
struct eframe {
|
|
struct sparc_stackf sf;
|
|
struct pt_regs pr;
|
|
};
|
|
|
|
/* Need to handle hardirq and softirq stacks. */
|
|
static int
|
|
kstack_valid(struct bt_info *bt, unsigned long sp)
|
|
{
|
|
unsigned long thread_info = SIZE(thread_info);
|
|
unsigned long base = bt->stackbase + thread_info;
|
|
unsigned long top = bt->stacktop - sizeof(struct eframe);
|
|
int rc = FALSE;
|
|
|
|
if (sp & (16U - 1))
|
|
goto out;
|
|
|
|
if ((sp >= base) && (sp <= top))
|
|
rc = TRUE;
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
static void
|
|
sparc64_print_eframe(struct bt_info *bt)
|
|
{
|
|
struct eframe k_entry;
|
|
struct pt_regs *regs = &k_entry.pr;
|
|
unsigned long efp;
|
|
unsigned int tt;
|
|
int rc;
|
|
struct reg_window window;
|
|
unsigned long rw;
|
|
|
|
efp = bt->stkptr + STACK_BIAS - TRACEREG_SZ - STACKFRAME_SZ;
|
|
if (!kstack_valid(bt, efp))
|
|
goto try_stacktop;
|
|
|
|
rc = readmem(efp, KVADDR, &k_entry, sizeof(k_entry),
|
|
"Stack frame and pt_regs.", RETURN_ON_ERROR);
|
|
if (rc && ((regs->magic & ~MAGIC_TT_MASK) == PT_REGS_MAGIC))
|
|
goto print_frame;
|
|
|
|
try_stacktop:
|
|
efp = bt->stacktop - sizeof(struct eframe);
|
|
rc = readmem(efp, KVADDR, &k_entry, sizeof(k_entry),
|
|
"Stack frame and pt_regs.", RETURN_ON_ERROR);
|
|
if (!rc)
|
|
goto out;
|
|
/* Kernel thread or not in kernel any longer? */
|
|
if ((regs->magic & ~MAGIC_TT_MASK) != PT_REGS_MAGIC)
|
|
goto out;
|
|
|
|
print_frame:
|
|
tt = regs->magic & MAGIC_TT_MASK;
|
|
fprintf(fp, "TSTATE=0x%lx TT=0x%x TPC=0x%lx TNPC=0x%lx\n",
|
|
regs->tstate, tt, regs->tpc, regs->tnpc);
|
|
fprintf(fp, " g0=0x%.16lx g1=0x%.16lx g2=0x%.16lx\n",
|
|
regs->u_regs[0],
|
|
regs->u_regs[1],
|
|
regs->u_regs[2]);
|
|
fprintf(fp, " g3=0x%.16lx g4=0x%.16lx g5=0x%.16lx\n",
|
|
regs->u_regs[3],
|
|
regs->u_regs[4],
|
|
regs->u_regs[5]);
|
|
#define ___INS (8)
|
|
fprintf(fp, " g6=0x%.16lx g7=0x%.16lx\n",
|
|
regs->u_regs[6],
|
|
regs->u_regs[7]);
|
|
fprintf(fp, " o0=0x%.16lx o1=0x%.16lx o2=0x%.16lx\n",
|
|
regs->u_regs[___INS+0],
|
|
regs->u_regs[___INS+1],
|
|
regs->u_regs[___INS+2]);
|
|
fprintf(fp, " o3=0x%.16lx o4=0x%.16lx o5=0x%.16lx\n",
|
|
regs->u_regs[___INS+3],
|
|
regs->u_regs[___INS+4],
|
|
regs->u_regs[___INS+5]);
|
|
fprintf(fp, " sp=0x%.16lx ret_pc=0x%.16lx\n",
|
|
regs->u_regs[___INS+6],
|
|
regs->u_regs[___INS+7]);
|
|
#undef ___INS
|
|
rw = bt->stkptr + STACK_BIAS;
|
|
if (!kstack_valid(bt, rw))
|
|
goto out;
|
|
rc = readmem(rw, KVADDR, &window, sizeof(window),
|
|
"Register window.", RETURN_ON_ERROR);
|
|
if (!rc)
|
|
goto out;
|
|
fprintf(fp, " l0=0x%.16lx l1=0x%.16lx l2=0x%.16lx\n",
|
|
window.locals[0], window.locals[1], window.locals[2]);
|
|
fprintf(fp, " l3=0x%.16lx l4=0x%.16lx l5=0x%.16lx\n",
|
|
window.locals[3], window.locals[4], window.locals[5]);
|
|
fprintf(fp, " l6=0x%.16lx l7=0x%.16lx\n",
|
|
window.locals[6], window.locals[7]);
|
|
fprintf(fp, " i0=0x%.16lx i1=0x%.16lx i2=0x%.16lx\n",
|
|
window.ins[0], window.ins[1], window.ins[2]);
|
|
fprintf(fp, " i3=0x%.16lx i4=0x%.16lx i5=0x%.16lx\n",
|
|
window.ins[3], window.ins[4], window.ins[5]);
|
|
fprintf(fp, " i6=0x%.16lx i7=0x%.16lx\n",
|
|
window.ins[6], window.ins[7]);
|
|
out:
|
|
return;
|
|
}
|
|
|
|
static int
|
|
sparc64_eframe_search(struct bt_info *bt)
|
|
{
|
|
sparc64_print_eframe(bt);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
sparc64_print_frame(struct bt_info *bt, int cnt, unsigned long ip,
|
|
unsigned long ksp)
|
|
{
|
|
char *symbol = closest_symbol(ip);
|
|
|
|
fprintf(fp, "#%d [%lx] %s at %lx\n", cnt, ksp, symbol, ip);
|
|
|
|
if (bt->flags & BT_LINE_NUMBERS) {
|
|
char buf[BUFSIZE];
|
|
|
|
get_line_number(ip, buf, FALSE);
|
|
if (strlen(buf))
|
|
fprintf(fp, "\t%s\n", buf);
|
|
}
|
|
}
|
|
|
|
static void
|
|
sparc64_back_trace(struct bt_info *bt)
|
|
{
|
|
unsigned long ip = bt->instptr;
|
|
unsigned long ksp = bt->stkptr;
|
|
struct reg_window window;
|
|
int cnt = 0;
|
|
int rc;
|
|
|
|
do {
|
|
if (!kstack_valid(bt, ksp + STACK_BIAS))
|
|
break;
|
|
rc = readmem(ksp + STACK_BIAS, KVADDR, &window, sizeof(window),
|
|
"KSP window fetch.", RETURN_ON_ERROR);
|
|
if (!rc)
|
|
goto out;
|
|
sparc64_print_frame(bt, cnt, ip, ksp);
|
|
ksp = window.ins[6];
|
|
ip = window.ins[7];
|
|
cnt++;
|
|
} while (cnt != 50);
|
|
sparc64_print_eframe(bt);
|
|
out:
|
|
return;
|
|
}
|
|
|
|
static ulong
|
|
sparc64_processor_speed(void)
|
|
{
|
|
int cpu;
|
|
unsigned long clock_tick;
|
|
struct syment *sp;
|
|
|
|
if (!MEMBER_EXISTS("cpuinfo_sparc", "clock_tick")) {
|
|
error(WARNING, "sparc64 expects clock_tick\n");
|
|
return 0UL;
|
|
}
|
|
|
|
sp = per_cpu_symbol_search("__cpu_data");
|
|
if (!sp)
|
|
return 0UL;
|
|
for (cpu = 0; cpu < kt->cpus; cpu++) {
|
|
if (!in_cpu_map(ONLINE, cpu))
|
|
continue;
|
|
if (!readmem(sp->value + kt->__per_cpu_offset[cpu] +
|
|
MEMBER_OFFSET("cpuinfo_sparc", "clock_tick"),
|
|
KVADDR, &clock_tick, sizeof(clock_tick),
|
|
"clock_tick", QUIET|RETURN_ON_ERROR))
|
|
continue;
|
|
return clock_tick/1000000;
|
|
}
|
|
return 0UL;
|
|
}
|
|
|
|
static ulong
|
|
sparc64_get_task_pgd(ulong task)
|
|
{
|
|
struct task_context *tc = task_to_context(task);
|
|
ulong pgd = NO_TASK;
|
|
|
|
if (!tc)
|
|
goto out;
|
|
readmem(tc->mm_struct + OFFSET(mm_struct_pgd), KVADDR,
|
|
&pgd, sizeof(unsigned long), "User pgd.", RETURN_ON_ERROR);
|
|
out:
|
|
return pgd;
|
|
}
|
|
|
|
static int
|
|
sparc64_uvtop(struct task_context *tc, ulong va, physaddr_t *ppaddr,
|
|
int verbose)
|
|
{
|
|
unsigned long pgd = sparc64_get_task_pgd(tc->task);
|
|
unsigned long paddr;
|
|
int rc = FALSE;
|
|
|
|
if (pgd == NO_TASK)
|
|
goto out;
|
|
paddr = sparc64_page_table_walk(pgd, va, verbose);
|
|
/* For now not_valid_pte skips checking for swap pte. */
|
|
if (paddr == not_valid_pte) {
|
|
*ppaddr = 0UL;
|
|
goto out;
|
|
}
|
|
*ppaddr = paddr;
|
|
rc = TRUE;
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
static unsigned long
|
|
sparc64_vmalloc_translate(unsigned long vaddr, int verbose)
|
|
{
|
|
unsigned long paddr = sparc64_page_table_walk(vt->kernel_pgd[0],
|
|
vaddr, verbose);
|
|
|
|
return paddr;
|
|
}
|
|
|
|
static unsigned long
|
|
sparc64_linear_translate(unsigned long vaddr)
|
|
{
|
|
unsigned long paddr = __pa(vaddr);
|
|
|
|
if (sparc64_verify_paddr(paddr) == FALSE)
|
|
error(FATAL,
|
|
"sparc64_linear_translate: This physical address"
|
|
" (0x%lx) is invalid.", paddr);
|
|
|
|
return paddr;
|
|
}
|
|
|
|
static int
|
|
sparc64_is_vmalloc_mapped(unsigned long vaddr)
|
|
{
|
|
struct machine_specific *ms = &sparc64_machine_specific;
|
|
int rc = 0;
|
|
|
|
if ((vaddr >= SPARC64_MODULES_VADDR && vaddr < SPARC64_MODULES_END) ||
|
|
(vaddr >= SPARC64_VMALLOC_START && vaddr < ms->vmalloc_end))
|
|
rc = 1;
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
sparc64_is_kvaddr(ulong vaddr)
|
|
{
|
|
return kimage_va_range(vaddr) ||
|
|
sparc64_is_linear_mapped(vaddr) ||
|
|
sparc64_is_vmalloc_mapped(vaddr);
|
|
}
|
|
|
|
static int
|
|
sparc64_kvtop(struct task_context *tc, ulong vaddr, physaddr_t *paddr,
|
|
int verbose)
|
|
{
|
|
unsigned long phys_addr;
|
|
int rc = FALSE;
|
|
|
|
if (kimage_va_range(vaddr)) {
|
|
phys_addr = kimage_va_translate(vaddr);
|
|
} else if (sparc64_is_vmalloc_mapped(vaddr)) {
|
|
phys_addr = sparc64_vmalloc_translate(vaddr, verbose);
|
|
if (phys_addr == not_valid_pte)
|
|
goto out;
|
|
} else if (sparc64_is_linear_mapped(vaddr)) {
|
|
phys_addr = sparc64_linear_translate(vaddr);
|
|
} else {
|
|
error(WARNING,
|
|
"This is an invalid kernel virtual address=0x%lx.",
|
|
vaddr);
|
|
goto out;
|
|
}
|
|
|
|
*paddr = phys_addr;
|
|
rc = TRUE;
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
sparc64_is_task_addr(ulong task)
|
|
{
|
|
int rc = FALSE;
|
|
int cpu;
|
|
|
|
if (sparc64_is_linear_mapped(task) || kimage_va_range(task))
|
|
rc = TRUE;
|
|
else {
|
|
for (cpu = 0; cpu < kt->cpus; cpu++)
|
|
if (task == tt->idle_threads[cpu]) {
|
|
rc = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
sparc64_is_uvaddr(ulong vaddr, struct task_context *tc)
|
|
{
|
|
return vaddr < SPARC64_USERSPACE_TOP;
|
|
}
|
|
|
|
static const char
|
|
*pte_page_size(unsigned long pte)
|
|
{
|
|
static const char *_4Mb = "4Mb";
|
|
static const char *_64Kb = "64Kb";
|
|
static const char *_8Kb = "8Kb";
|
|
static const char *_ns = "Not Supported";
|
|
const char *result;
|
|
|
|
switch (pte & _PAGE_SZALL_4V) {
|
|
case _PAGE_SZ8K_4V:
|
|
result = _8Kb;
|
|
break;
|
|
case _PAGE_SZ64K_4V:
|
|
result = _64Kb;
|
|
break;
|
|
case _PAGE_SZ4MB_4V:
|
|
result = _4Mb;
|
|
break;
|
|
default:
|
|
result = _ns;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static int
|
|
sparc64_translate_pte(unsigned long pte, void *physaddr, ulonglong unused)
|
|
{
|
|
unsigned long paddr = pte_to_pa(pte);
|
|
int rc = FALSE;
|
|
int cnt = 0;
|
|
|
|
/* Once again not handling swap pte.*/
|
|
if ((pte & _PAGE_VALID) == 0UL)
|
|
goto out;
|
|
if (pte & _PAGE_NFO_4V)
|
|
fprintf(fp, "%sNoFaultOn", cnt++ ? "|" : "");
|
|
if (pte & _PAGE_MODIFIED_4V)
|
|
fprintf(fp, "%sModified", cnt++ ? "|" : "");
|
|
if (pte & _PAGE_ACCESSED_4V)
|
|
fprintf(fp, "%sAccessed", cnt++ ? "|" : "");
|
|
if (pte & _PAGE_READ_4V)
|
|
fprintf(fp, "%sReadSoftware", cnt++ ? "|" : "");
|
|
if (pte & _PAGE_WRITE_4V)
|
|
fprintf(fp, "%sWriteSoftware", cnt++ ? "|" : "");
|
|
if (pte & _PAGE_P_4V)
|
|
fprintf(fp, "%sPriv", cnt++ ? "|" : "");
|
|
if (pte & _PAGE_EXEC_4V)
|
|
fprintf(fp, "%sExecute", cnt++ ? "|" : "");
|
|
if (pte & _PAGE_W_4V)
|
|
fprintf(fp, "%sWritable", cnt++ ? "|" : "");
|
|
if (pte & _PAGE_PRESENT_4V)
|
|
fprintf(fp, "%sPresent", cnt++ ? "|" : "");
|
|
fprintf(fp, "|PageSize(%s)\n", pte_page_size(pte));
|
|
if (physaddr)
|
|
*(unsigned long *)physaddr = paddr;
|
|
rc = TRUE;
|
|
out:
|
|
return rc;
|
|
}
|
|
|
|
static void
|
|
sparc64_get_frame(struct bt_info *bt, unsigned long *r14, unsigned long *r15)
|
|
{
|
|
unsigned long ksp_offset = sparc64_ksp_offset + bt->tc->thread_info;
|
|
unsigned long ksp;
|
|
int rc;
|
|
|
|
/* We need thread_info's ksp. This is the stack for sleeping threads
|
|
* and captured during switch_to. The rest is fetchable from there.
|
|
*/
|
|
rc = readmem(ksp_offset, KVADDR, &ksp, sizeof(ksp), "KSP Fetch.",
|
|
RETURN_ON_ERROR);
|
|
if (!rc)
|
|
goto out;
|
|
*r14 = ksp;
|
|
*r15 = symbol_value("switch_to_pc");
|
|
out:
|
|
return;
|
|
}
|
|
|
|
static void
|
|
sparc64_get_dumpfile_stack_frame(struct bt_info *bt, unsigned long *psp,
|
|
unsigned long *ppc)
|
|
{
|
|
unsigned long *pt_regs;
|
|
|
|
pt_regs = (unsigned long *)bt->machdep;
|
|
|
|
if (!pt_regs)
|
|
fprintf(fp, "0%lx: registers not saved\n", bt->task);
|
|
|
|
/* pt_regs can be unaligned */
|
|
BCOPY(&pt_regs[30], psp, sizeof(ulong));
|
|
BCOPY(&pt_regs[33], ppc, sizeof(ulong));
|
|
}
|
|
|
|
static void
|
|
sparc64_get_stack_frame(struct bt_info *bt, unsigned long *pcp,
|
|
unsigned long *psp)
|
|
{
|
|
unsigned long r14, r15;
|
|
|
|
if (DUMPFILE() && is_task_active(bt->task))
|
|
sparc64_get_dumpfile_stack_frame(bt, &r14, &r15);
|
|
else
|
|
sparc64_get_frame(bt, &r14, &r15);
|
|
if (pcp)
|
|
*pcp = r15;
|
|
if (psp)
|
|
*psp = r14;
|
|
}
|
|
|
|
static int
|
|
sparc64_get_kvaddr_ranges(struct vaddr_range *vrp)
|
|
{
|
|
struct machine_specific *ms = &sparc64_machine_specific;
|
|
|
|
vrp[0].type = KVADDR_UNITY_MAP;
|
|
vrp[0].start = ms->page_offset;
|
|
vrp[0].end = ~0ULL;
|
|
vrp[1].type = KVADDR_VMALLOC;
|
|
vrp[1].start = SPARC64_VMALLOC_START;
|
|
vrp[1].end = ms->vmalloc_end;
|
|
vrp[2].type = KVADDR_START_MAP;
|
|
vrp[2].start = symbol_value("_start");
|
|
vrp[2].end = symbol_value("_end");
|
|
vrp[3].type = KVADDR_MODULES;
|
|
vrp[3].start = SPARC64_MODULES_VADDR;
|
|
vrp[3].end = SPARC64_MODULES_END;
|
|
return 4;
|
|
}
|
|
|
|
static void
|
|
sparc64_get_crash_notes(void)
|
|
{
|
|
unsigned long *notes_ptrs, size, crash_notes_address;
|
|
int ret;
|
|
|
|
if (!symbol_exists("crash_notes")) {
|
|
error(WARNING, "Could not retrieve crash_notes.");
|
|
goto out;
|
|
}
|
|
|
|
crash_notes_address = symbol_value("crash_notes");
|
|
size = kt->cpus * sizeof(notes_ptrs[0]);
|
|
notes_ptrs = (unsigned long *) GETBUF(size);
|
|
ret = readmem(crash_notes_address, KVADDR, notes_ptrs, size,
|
|
"crash_notes", RETURN_ON_ERROR);
|
|
if (!ret)
|
|
goto out2;
|
|
out2:
|
|
FREEBUF(notes_ptrs);
|
|
out:
|
|
return;
|
|
}
|
|
|
|
static void
|
|
sparc64_init_kstack_info(void)
|
|
{
|
|
sparc64_ksp_offset = MEMBER_OFFSET("thread_info", "ksp");
|
|
}
|
|
|
|
static void
|
|
sparc64_init_irq_stacks(void)
|
|
{
|
|
void *irq_stack;
|
|
unsigned long stack_size;
|
|
|
|
stack_size = get_array_length("hardirq_stack", NULL, 0) *
|
|
sizeof(unsigned long);
|
|
irq_stack = malloc(stack_size);
|
|
if (!irq_stack)
|
|
error(FATAL, "malloc failure in sparc64_init_irq_stacks");
|
|
|
|
get_symbol_data("hardirq_stack", stack_size, irq_stack);
|
|
tt->hardirq_ctx = irq_stack;
|
|
|
|
stack_size = get_array_length("softirq_stack", NULL, 0) *
|
|
sizeof(unsigned long);
|
|
irq_stack = malloc(stack_size);
|
|
if (!irq_stack)
|
|
error(FATAL, "malloc failure in sparc64_init_irq_stacks");
|
|
|
|
get_symbol_data("softirq_stack", stack_size, irq_stack);
|
|
tt->softirq_ctx = irq_stack;
|
|
}
|
|
|
|
static void
|
|
sparc64_init_vmemmap_info(void)
|
|
{
|
|
struct machine_specific *ms = &sparc64_machine_specific;
|
|
unsigned long page_struct_size = STRUCT_SIZE("page");
|
|
|
|
/*
|
|
* vmemmap memory is addressed as vmalloc memory, so we
|
|
* treat it as an etension of the latter.
|
|
*/
|
|
ms->vmalloc_end +=
|
|
((1UL << (machdep->max_physmem_bits - PAGE_SHIFT)) *
|
|
page_struct_size);
|
|
}
|
|
|
|
static void
|
|
sparc64_init_cpu_info(void)
|
|
{
|
|
unsigned long trap_block, per_cpu_base_offset, per_cpu_base;
|
|
unsigned long trap_per_cpu;
|
|
int cpu;
|
|
|
|
if (!symbol_exists("trap_block"))
|
|
error(FATAL, "sparc64 requires trap_block symbol.\n");
|
|
|
|
trap_block = symbol_value("trap_block");
|
|
if (!MEMBER_EXISTS("trap_per_cpu", "__per_cpu_base"))
|
|
error(FATAL, "sparc64 requires __per_cpu_base.\n");
|
|
trap_per_cpu = STRUCT_SIZE("trap_per_cpu");
|
|
per_cpu_base_offset = MEMBER_OFFSET("trap_per_cpu", "__per_cpu_base");
|
|
for (cpu = 0; cpu < NR_CPUS; cpu++,
|
|
trap_block = trap_block + trap_per_cpu) {
|
|
|
|
if (!in_cpu_map(POSSIBLE, cpu))
|
|
continue;
|
|
readmem(trap_block + per_cpu_base_offset, KVADDR,
|
|
&per_cpu_base, sizeof(per_cpu_base),
|
|
"sparc64: per_cpu_base", FAULT_ON_ERROR);
|
|
kt->__per_cpu_offset[cpu] = per_cpu_base;
|
|
}
|
|
}
|
|
|
|
void
|
|
sparc64_init(int when)
|
|
{
|
|
struct machine_specific *ms = &sparc64_machine_specific;
|
|
|
|
switch (when) {
|
|
case SETUP_ENV:
|
|
machdep->process_elf_notes = process_elf64_notes;
|
|
break;
|
|
case PRE_SYMTAB:
|
|
machdep->machspec = ms;
|
|
machdep->verify_paddr = sparc64_verify_paddr;
|
|
machdep->verify_symbol = sparc64_verify_symbol;
|
|
machdep->verify_line_number = sparc64_verify_line_number;
|
|
|
|
if (pc->flags & KERNEL_DEBUG_QUERY)
|
|
return;
|
|
machdep->flags |= MACHDEP_BT_TEXT;
|
|
if (machdep->cmdline_args[0])
|
|
sparc64_parse_cmdline_args();
|
|
break;
|
|
|
|
case PRE_GDB:
|
|
machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
|
|
|
|
machdep->pagesize = memory_page_size();
|
|
machdep->pageshift = ffs(machdep->pagesize) - 1;
|
|
machdep->pageoffset = machdep->pagesize - 1;
|
|
machdep->pagemask = ~((ulonglong) machdep->pageoffset);
|
|
machdep->stacksize = machdep->pagesize * 2;
|
|
|
|
machdep->eframe_search = sparc64_eframe_search;
|
|
machdep->back_trace = sparc64_back_trace;
|
|
machdep->processor_speed = sparc64_processor_speed;
|
|
|
|
machdep->uvtop = sparc64_uvtop;
|
|
machdep->kvtop = sparc64_kvtop;
|
|
machdep->get_task_pgd = sparc64_get_task_pgd;
|
|
|
|
machdep->dump_irq = generic_dump_irq;
|
|
|
|
machdep->get_stack_frame = sparc64_get_stack_frame;
|
|
machdep->get_stackbase = generic_get_stackbase;
|
|
machdep->get_stacktop = generic_get_stacktop;
|
|
machdep->translate_pte = sparc64_translate_pte;
|
|
machdep->memory_size = generic_memory_size;
|
|
|
|
machdep->vmalloc_start = sparc64_vmalloc_start;
|
|
machdep->is_task_addr = sparc64_is_task_addr;
|
|
machdep->is_kvaddr = sparc64_is_kvaddr;
|
|
machdep->is_uvaddr = sparc64_is_uvaddr;
|
|
machdep->dis_filter = sparc64_dis_filter;
|
|
machdep->get_smp_cpus = sparc64_get_smp_cpus;
|
|
machdep->clear_machdep_cache = sparc64_clear_machdep_cache;
|
|
machdep->get_kvaddr_ranges = sparc64_get_kvaddr_ranges;
|
|
machdep->cmd_mach = sparc64_cmd_mach;
|
|
machdep->init_kernel_pgd = sparc64_init_kernel_pgd;
|
|
machdep->value_to_symbol = generic_machdep_value_to_symbol;
|
|
machdep->get_irq_affinity = generic_get_irq_affinity;
|
|
machdep->show_interrupts = generic_show_interrupts;
|
|
|
|
pt_level_alloc(&machdep->pgd, "Can't malloc pgd space.");
|
|
pt_level_alloc(&machdep->pud, "Can't malloc pud space.");
|
|
pt_level_alloc(&machdep->pmd, "Can't malloc pmd space.");
|
|
pt_level_alloc(&machdep->ptbl, "Can't malloc ptbl space.");
|
|
pt_clear_cache();
|
|
sparc64_phys_base();
|
|
sparc64_kimage_limits();
|
|
break;
|
|
|
|
case POST_GDB:
|
|
get_symbol_data("PAGE_OFFSET", sizeof(unsigned long),
|
|
&ms->page_offset);
|
|
machdep->kvbase = symbol_value("_stext");
|
|
machdep->identity_map_base = (ulong) PAGE_OFFSET;
|
|
machdep->ptrs_per_pgd = PTRS_PER_PGD;
|
|
get_symbol_data("VMALLOC_END", sizeof(unsigned long),
|
|
&ms->vmalloc_end);
|
|
machdep->section_size_bits = _SECTION_SIZE_BITS;
|
|
if (kernel_symbol_exists("nr_irqs"))
|
|
get_symbol_data("nr_irqs", sizeof(unsigned int),
|
|
&machdep->nr_irqs);
|
|
sparc64_init_vmemmap_info();
|
|
sparc64_init_cpu_info();
|
|
sparc64_init_kstack_info();
|
|
sparc64_init_irq_stacks();
|
|
break;
|
|
case POST_VM:
|
|
if (!ACTIVE())
|
|
sparc64_get_crash_notes();
|
|
break;
|
|
case POST_INIT:
|
|
break;
|
|
|
|
case LOG_ONLY:
|
|
machdep->machspec = ms;
|
|
machdep->kvbase = kt->vmcoreinfo._stext_SYMBOL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
sparc64_dump_machdep_table(ulong arg)
|
|
{
|
|
int i, others;
|
|
|
|
others = 0;
|
|
fprintf(fp, " flags: %lx (", machdep->flags);
|
|
if (machdep->flags & MACHDEP_BT_TEXT)
|
|
fprintf(fp, "%sMACHDEP_BT_TEXT", 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: %ld\n", machdep->mhz);
|
|
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: sparc64_eframe_search()\n");
|
|
fprintf(fp, " back_trace: sparc64_back_trace()\n");
|
|
fprintf(fp, " processor_speed: sparc64_processor_speed()\n");
|
|
fprintf(fp, " uvtop: sparc64_uvtop()\n");
|
|
fprintf(fp, " kvtop: sparc64_kvtop()\n");
|
|
fprintf(fp, " get_task_pgd: sparc64_get_task_pgd()\n");
|
|
fprintf(fp, " dump_irq: generic_dump_irq()\n");
|
|
fprintf(fp, " get_stack_frame: sparc64_get_stack_frame()\n");
|
|
fprintf(fp, " get_stackbase: generic_get_stackbase()\n");
|
|
fprintf(fp, " get_stacktop: generic_get_stacktop()\n");
|
|
fprintf(fp, " translate_pte: sparc64_translate_pte()\n");
|
|
fprintf(fp, " memory_size: generic_memory_size()\n");
|
|
fprintf(fp, " vmalloc_start: sparc64_vmalloc_start()\n");
|
|
fprintf(fp, " is_task_addr: sparc64_is_task_addr()\n");
|
|
fprintf(fp, " verify_symbol: sparc64_verify_symbol()\n");
|
|
fprintf(fp, " dis_filter: sparc64_dis_filter()\n");
|
|
fprintf(fp, " cmd_mach: sparc64_cmd_mach()\n");
|
|
fprintf(fp, " get_smp_cpus: sparc64_get_smp_cpus()\n");
|
|
fprintf(fp, " is_kvaddr: sparc64_is_kvaddr()\n");
|
|
fprintf(fp, " is_uvaddr: sparc64_is_uvaddr()\n");
|
|
fprintf(fp, " verify_paddr: sparc64_verify_paddr()\n");
|
|
fprintf(fp, " get_kvaddr_ranges: sparc64_get_kvaddr_ranges()\n");
|
|
fprintf(fp, " get_irq_affinity: generic_get_irq_affinity()\n");
|
|
fprintf(fp, " show_interrupts: generic_show_interrupts()\n");
|
|
fprintf(fp, " xendump_p2m_create: NULL\n");
|
|
fprintf(fp, "xen_kdump_p2m_create: NULL\n");
|
|
fprintf(fp, " line_number_hooks: NULL\n");
|
|
fprintf(fp, " last_pgd_read: %lx\n", machdep->last_pgd_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, "clear_machdep_cache: sparc64_clear_machdep_cache()\n");
|
|
fprintf(fp, " pgd: %lx\n", (ulong)machdep->pgd);
|
|
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);
|
|
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);
|
|
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, " machspec: %lx\n", (ulong)machdep->machspec);
|
|
fprintf(fp, " page_offset: %lx\n",
|
|
machdep->machspec->page_offset);
|
|
fprintf(fp, " vmalloc_end: %lx\n",
|
|
machdep->machspec->vmalloc_end);
|
|
}
|
|
|
|
#endif /* SPARC64 */
|