Logo Search packages:      
Sourcecode: makedumpfile version File versions  Download package

ia64.c

/*
 * ia64.c
 *
 * Copyright (C) 2006, 2007, 2008  NEC 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 __ia64__

#include "makedumpfile.h"


/*
 *  vmalloc() starting address is either the traditional 0xa000000000000000 or
 *  bumped up in 2.6 to 0xa000000200000000.
 */
int
is_vmalloc_addr_ia64(unsigned long vaddr)
{
      return ((vaddr >= info->vmalloc_start) &&
                  (vaddr < (unsigned long)KERNEL_UNCACHED_BASE));
}

int
get_phys_base_ia64(void)
{
      int i;
      struct pt_load_segment *pls;

      /*
       *  Default to 64MB.
       */
      info->phys_base = DEFAULT_PHYS_START;

      for (i = 0; i < info->num_load_memory; i++) {
            pls = &info->pt_load_segments[i];
            if (VADDR_REGION(pls->virt_start) == KERNEL_VMALLOC_REGION) {

                  info->phys_base = pls->phys_start;
                  break;
            }
      }
      return TRUE;
}

int
get_machdep_info_ia64(void)
{
      /*
       * Get kernel_start and vmalloc_start.
       */
      if (SYMBOL(_stext) == NOT_FOUND_SYMBOL)
            return FALSE;

      info->kernel_start = SYMBOL(_stext);

      if (VADDR_REGION(info->kernel_start) == KERNEL_VMALLOC_REGION)
            info->vmalloc_start = info->kernel_start + 4*1024UL*1024UL*1024UL;
      else
            info->vmalloc_start = KERNEL_VMALLOC_BASE;

      /*
       * Check the pgtable (3 Levels or 4 Levels).
       */
      if ((vt.mem_flags & MEMORY_PAGETABLE_4L)
          || !strncmp(SRCFILE(pud_t), STR_PUD_T_4L, strlen(STR_PUD_T_4L))) {
            vt.mem_flags |= MEMORY_PAGETABLE_4L;
            DEBUG_MSG("PAGETABLE_4L : ON\n");
      } else if ((vt.mem_flags & MEMORY_PAGETABLE_3L)
          || !strncmp(SRCFILE(pud_t), STR_PUD_T_3L, strlen(STR_PUD_T_3L))) {
            vt.mem_flags |= MEMORY_PAGETABLE_3L;
            DEBUG_MSG("PAGETABLE_3L : ON\n");
      } else {
            MSG("Can't distinguish the pgtable.\n");
      }

      info->section_size_bits = _SECTION_SIZE_BITS;
      info->max_physmem_bits  = _MAX_PHYSMEM_BITS;

      return TRUE;
}

/*
 * Translate a virtual address to a physical address by using 3 levels paging.
 */
unsigned long long
vtop3_ia64(unsigned long vaddr)
{
      unsigned long long paddr, temp, page_dir, pgd_pte, page_middle, pmd_pte;
      unsigned long long page_table, pte;

      if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) {
            ERRMSG("Can't get the symbol of swapper_pg_dir.\n");
            return NOT_PADDR;
      }

      /*
       * Get PGD
       */
      temp = vaddr & MASK_PGD_3L;
      temp = temp >> (PGDIR_SHIFT_3L - 3);
      page_dir = SYMBOL(swapper_pg_dir) + temp;
      if (!readmem(VADDR, page_dir, &pgd_pte, sizeof pgd_pte)) {
            ERRMSG("Can't get pgd_pte (page_dir:%llx).\n", page_dir);
            return NOT_PADDR;
      }
      if (info->vaddr_for_vtop == vaddr)
            MSG("  PGD : %16llx => %16llx\n", page_dir, pgd_pte);

      /*
       * Get PMD
       */
      temp = vaddr & MASK_PMD;
      temp = temp >> (PMD_SHIFT - 3);
      page_middle = pgd_pte + temp;
      if (!readmem(PADDR, page_middle, &pmd_pte, sizeof pmd_pte)) {
            ERRMSG("Can't get pmd_pte (page_middle:%llx).\n", page_middle);
            return NOT_PADDR;
      }
      if (info->vaddr_for_vtop == vaddr)
            MSG("  PMD : %16llx => %16llx\n", page_middle, pmd_pte);

      /*
       * Get PTE
       */
      temp = vaddr & MASK_PTE;
      temp = temp >> (PAGESHIFT() - 3);
      page_table = pmd_pte + temp;
      if (!readmem(PADDR, page_table, &pte, sizeof pte)) {
            ERRMSG("Can't get pte (page_table:%llx).\n", page_table);
            return NOT_PADDR;
      }
      if (info->vaddr_for_vtop == vaddr)
            MSG("  PTE : %16llx => %16llx\n", page_table, pte);

      /*
       * Get physical address
       */
      temp = vaddr & MASK_POFFSET;
      paddr = (pte & _PAGE_PPN_MASK) + temp;

      return paddr;
}

/*
 * Translate a virtual address to a physical address by using 4 levels paging.
 */
unsigned long long
vtop4_ia64(unsigned long vaddr)
{
      unsigned long long paddr, temp, page_dir, pgd_pte, page_upper, pud_pte;
      unsigned long long page_middle, pmd_pte, page_table, pte;

      if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) {
            ERRMSG("Can't get the symbol of swapper_pg_dir.\n");
            return NOT_PADDR;
      }

      /*
       * Get PGD
       */
      temp = vaddr & MASK_PGD_4L;
      temp = temp >> (PGDIR_SHIFT_4L - 3);
      page_dir = SYMBOL(swapper_pg_dir) + temp;
      if (!readmem(VADDR, page_dir, &pgd_pte, sizeof pgd_pte)) {
            ERRMSG("Can't get pgd_pte (page_dir:%llx).\n", page_dir);
            return NOT_PADDR;
      }
      if (info->vaddr_for_vtop == vaddr)
            MSG("  PGD : %16llx => %16llx\n", page_dir, pgd_pte);

      /*
       * Get PUD
       */
      temp = vaddr & MASK_PUD;
      temp = temp >> (PUD_SHIFT - 3);
      page_upper = pgd_pte + temp;
      if (!readmem(PADDR, page_upper, &pud_pte, sizeof pud_pte)) {
            ERRMSG("Can't get pud_pte (page_upper:%llx).\n", page_upper);
            return NOT_PADDR;
      }
      if (info->vaddr_for_vtop == vaddr)
            MSG("  PUD : %16llx => %16llx\n", page_upper, pud_pte);

      /*
       * Get PMD
       */
      temp = vaddr & MASK_PMD;
      temp = temp >> (PMD_SHIFT - 3);
      page_middle = pud_pte + temp;
      if (!readmem(PADDR, page_middle, &pmd_pte, sizeof pmd_pte)) {
            ERRMSG("Can't get pmd_pte (page_middle:%llx).\n", page_middle);
            return NOT_PADDR;
      }
      if (info->vaddr_for_vtop == vaddr)
            MSG("  PMD : %16llx => %16llx\n", page_middle, pmd_pte);

      /*
       * Get PTE
       */
      temp = vaddr & MASK_PTE;
      temp = temp >> (PAGESHIFT() - 3);
      page_table = pmd_pte + temp;
      if (!readmem(PADDR, page_table, &pte, sizeof pte)) {
            ERRMSG("Can't get pte (page_table:%llx).\n", page_table);
            return NOT_PADDR;
      }
      if (info->vaddr_for_vtop == vaddr)
            MSG("  PTE : %16llx => %16llx\n", page_table, pte);

      /*
       * Get physical address
       */
      temp = vaddr & MASK_POFFSET;
      paddr = (pte & _PAGE_PPN_MASK) + temp;

      return paddr;
}

unsigned long long
vtop_ia64(unsigned long vaddr)
{
      unsigned long long paddr;

      if (VADDR_REGION(vaddr) != KERNEL_VMALLOC_REGION) {
            ERRMSG("vaddr(%lx) is not KERNEL_VMALLOC_REGION.\n", vaddr);
            return NOT_PADDR;
      }
      paddr = vaddr_to_paddr_general(vaddr);
      if (paddr != NOT_PADDR)
            return paddr;

      if (!is_vmalloc_addr_ia64(vaddr)) {
            paddr = vaddr - info->kernel_start +
                  (info->phys_base & KERNEL_TR_PAGE_MASK);
            return paddr;
      }

      if (vt.mem_flags & MEMORY_PAGETABLE_4L)
            return vtop4_ia64(vaddr);
      else
            return vtop3_ia64(vaddr);
}

/*
 * Translate a virtual address to physical address.
 */
unsigned long long
vaddr_to_paddr_ia64(unsigned long vaddr)
{
      unsigned long long paddr;

      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;

            case KERNEL_VMALLOC_REGION:
                  paddr = vtop_ia64(vaddr);
                  break;

            default:
                  ERRMSG("Unknown region (%ld)\n", VADDR_REGION(vaddr));
                  return 0x0;
      }
      return paddr;
}

/*
 * for Xen extraction
 */
unsigned long long
kvtop_xen_ia64(unsigned long kvaddr)
{
      unsigned long long addr, dirp, entry;

      if (!is_xen_vaddr(kvaddr))
            return NOT_PADDR;

      if (is_direct(kvaddr))
            return (unsigned long)kvaddr - DIRECTMAP_VIRT_START;

      if (!is_frame_table_vaddr(kvaddr))
            return NOT_PADDR;

      addr = kvaddr - VIRT_FRAME_TABLE_ADDR;

      dirp = SYMBOL(frametable_pg_dir) - DIRECTMAP_VIRT_START;
      dirp += ((addr >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) * sizeof(unsigned long long);
      if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry)))
            return NOT_PADDR;

      dirp = entry & _PFN_MASK;
      if (!dirp)
            return NOT_PADDR;

      dirp += ((addr >> PMD_SHIFT) & (PTRS_PER_PMD - 1)) * sizeof(unsigned long long);
      if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry)))
            return NOT_PADDR;

      dirp = entry & _PFN_MASK;
      if (!dirp)
            return NOT_PADDR;

      dirp += ((addr >> PAGESHIFT()) & (PTRS_PER_PTE - 1)) * sizeof(unsigned long long);
      if (!readmem(MADDR_XEN, dirp, &entry, sizeof(entry)))
            return NOT_PADDR;

      if (!(entry & _PAGE_P))
            return NOT_PADDR;

      entry = (entry & _PFN_MASK) + (addr & ((1UL << PAGESHIFT()) - 1));

      return entry;
}

int
get_xen_info_ia64(void)
{
      unsigned long xen_start, xen_end, xen_heap_start;
      int i;

      info->frame_table_vaddr = VIRT_FRAME_TABLE_ADDR; /* "frame_table" is same value */

      if (SYMBOL(xenheap_phys_end) == NOT_FOUND_SYMBOL) {
            ERRMSG("Can't get the symbol of xenheap_phys_end.\n");
            return FALSE;
      }
      if (!readmem(VADDR_XEN, SYMBOL(xenheap_phys_end), &xen_end,
            sizeof(xen_end))) {
            ERRMSG("Can't get the value of xenheap_phys_end.\n");
            return FALSE;
      }
      if (SYMBOL(xen_pstart) == NOT_FOUND_SYMBOL) {
            ERRMSG("Can't get the symbol of xen_pstart.\n");
            return FALSE;
      }
      if (!readmem(VADDR_XEN, SYMBOL(xen_pstart), &xen_start,
          sizeof(xen_start))) {
            ERRMSG("Can't get the value of xen_pstart.\n");
            return FALSE;
      }
      info->xen_heap_end = (xen_end >> PAGESHIFT());
      info->xen_heap_start = (xen_start >> PAGESHIFT());

      if (SYMBOL(xen_heap_start) == NOT_FOUND_SYMBOL) {
            ERRMSG("Can't get the symbol of xen_heap_start.\n");
            return FALSE;
      }
      if (!readmem(VADDR_XEN, SYMBOL(xen_heap_start), &xen_heap_start,
            sizeof(xen_heap_start))) {
            ERRMSG("Can't get the value of xen_heap_start.\n");
            return FALSE;
      }
      for (i = 0; i < info->num_domain; i++) {
            info->domain_list[i].pickled_id = (unsigned int)
                  (info->domain_list[i].domain_addr - xen_heap_start);
      }

      return TRUE;
}

#endif /* ia64 */


Generated by  Doxygen 1.6.0   Back to index