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

kl_page_i386.c

/*
 * $Id: kl_page_i386.c,v 1.1 2004/12/21 23:26:20 tjm Exp $
 *
 * This file is part of libklib.
 * A library which provides access to Linux system kernel dumps.
 *
 * Created by Silicon Graphics, Inc.
 * Contributions by IBM, NEC, and others
 *
 * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
 * Copyright (C) 2001, 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
 * Copyright 2000 Junichi Nomura, NEC Solutions <j-nomura@ce.jp.nec.com>
 *
 * This code is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version. See the file COPYING for more
 * information.
 */

#include <klib.h>

#define _DBG_COMPONENT KL_DBGCOMP_MEMMAP

/*
 * declarations of static functions
 */
static kaddr_t _kl_pgd_offset_i386(
      kaddr_t         /* kernel virtual address of page directory */,
      kaddr_t         /* kernel virtual address */);

static kaddr_t _kl_pmd_offset_i386(
      kaddr_t         /* kernel virtual address of page middle directory */,
      kaddr_t         /* kernel virtual address */);

static kaddr_t _kl_pte_offset_i386(
      kaddr_t         /* kernel virtual address of page table */,
      kaddr_t         /* kernel virtual address */);

/*
 * function definitions
 */

/* page table traversal functions */
static kaddr_t
_kl_pgd_offset_i386(kaddr_t pgd_base, kaddr_t vaddr)
{
      kaddr_t pgd_off, pmd_base;

      if(KL_KERNEL_FLAGS & KL_IS_PAE_I386){
            /* PAE: pgd entries are 64 bit */
            pgd_off = ((vaddr >> KL_PGDIR_SHIFT_I386_PAE) &
                     (KL_PTRS_PER_PGD_I386_PAE - 1)) * 8;
            kl_trace4(0,"pgd_off: %"FMTPTR"x\n", pgd_off);
            pmd_base = KL_READ_UINT64(pgd_base + pgd_off -
                                KL_PAGE_OFFSET_I386);
      } else {
            /* non-PAE */
            pgd_off = ((vaddr >> KL_PGDIR_SHIFT_I386) &
                     (KL_PTRS_PER_PGD_I386 - 1)) * KL_NBPW;
            kl_trace4(0,"pgd_off: %"FMTPTR"x\n", pgd_off);
            pmd_base = KL_READ_PTR(pgd_base + pgd_off -
                               KL_PAGE_OFFSET_I386);
      }

      return pmd_base;
}

static kaddr_t
_kl_pmd_offset_i386(kaddr_t pmd_base, kaddr_t vaddr)
{
      kaddr_t pmd_off, pte_base;

      if(KL_KERNEL_FLAGS & KL_IS_PAE_I386){
            /* PAE: pmd entries are 64 bit */
            pmd_off = ((vaddr >> KL_PMD_SHIFT_I386_PAE) &
                     (KL_PTRS_PER_PMD_I386_PAE - 1)) * 8;
            kl_trace4(0,"pmd_off: %"FMTPTR"x\n", pmd_off);
            pte_base = KL_READ_UINT64(pmd_base + pmd_off);
            return pte_base;
      } else {
            /* non-PAE: nothing to do for 2-level paging */
            return pmd_base;
      }
}

static kaddr_t
_kl_pte_offset_i386(kaddr_t pte_base, kaddr_t vaddr)
{
      kaddr_t pte_off, pte_val;

      if(KL_KERNEL_FLAGS & KL_IS_PAE_I386){
            pte_off = ((vaddr >> KL_PAGE_SHIFT_I386) &
                     (KL_PTRS_PER_PTE_I386_PAE - 1)) * 8;
            kl_trace4(0,"pte_off: %"FMTPTR"x\n", pte_off);
            pte_val = KL_READ_UINT64(pte_base + pte_off);

      } else {
            pte_off = ((vaddr >> KL_PAGE_SHIFT_I386) &
                     (KL_PTRS_PER_PTE_I386 - 1)) * KL_NBPW;
            kl_trace4(0,"pte_off: %"FMTPTR"x\n", pte_off);
            pte_val = KL_READ_PTR(pte_base + pte_off);
      }

      return pte_val;
}

/* lookup virtual address in page tables */
kaddr_t kl_mmap_virtop_i386(kaddr_t vaddr, void *mmp)
{
      kaddr_t pgd_base, pmd_base;
      kaddr_t pte_base, pte_val, paddr=0;

      kl_trace4(0,"vaddr: %"FMTPTR"x\n", vaddr);
      /* get the pgd entry */
      pgd_base = kl_kaddr(mmp, "mm_struct", "pgd");
      kl_trace4(0,"pgd_base: %"FMTPTR"x\n", pgd_base);
      pmd_base = _kl_pgd_offset_i386(pgd_base,vaddr);
      kl_trace4(0,"pmd_base: %"FMTPTR"x\n", pmd_base);
      if (KL_ERROR) {
            KL_ERROR = KLE_INVALID_MAPPING;
            kl_trace3(0, "Could not read pgd entry "
                   "for vaddr=%"FMTPTR"x\n", vaddr);
            return(0);
      }

      if(KL_KERNEL_FLAGS & KL_IS_PAE_I386){
            /* get the pmd entry */
            pmd_base &= KL_PMD_BASE_MASK_I386;
            pte_base = _kl_pmd_offset_i386(pmd_base, vaddr);
            kl_trace4(0,"pte_base: %"FMTPTR"x\n", pte_base);
            if (KL_ERROR) {
                  KL_ERROR = KLE_INVALID_MAPPING;
                  kl_trace3(0, "Could not read pmd entry (PAE) "
                          "for vaddr=%"FMTPTR"x\n", vaddr);
                  return(0);
            }

            /* check for use of page size extension, i.e. 2MB page */
            if(pte_base & KL_PAGE_PSE_I386) {
                  if (kl_pte_none_i386(pte_base)){
                        KL_ERROR = KLE_INVALID_MAPPING;
                        kl_trace3(0, "invalid page table entry "
                                "(PAE/PSE) for vaddr=%"FMTPTR"x\n",
                                vaddr);
                        return(0);
                  }
                  if (!kl_pte_present_i386(pte_base)){
                        KL_ERROR = KLE_PAGE_NOT_PRESENT;
                        kl_trace3(0, "page not present (PAE/PSE) "
                                "for vaddr=%"FMTPTR"x\n", vaddr);
                        return(0);
                  }

                  paddr = (pte_base & KL_PSE_PAGE_MASK_I386_PAE) | 
                        (vaddr & KL_PSE_OFFSET_MASK_I386_PAE);
            } else {
                  if (kl_pmd_bad_i386(pte_base) ||
                      kl_pmd_none_i386(pte_base)){
                        KL_ERROR = KLE_INVALID_MAPPING;
                        kl_trace3(0, "invalid pmd entry (PAE) "
                                "for vaddr=%"FMTPTR"x\n", vaddr);
                        return(0);
                  }
                  /* get the pte */
                  pte_base &= KL_PT_BASE_MASK_I386;
                  pte_val = _kl_pte_offset_i386(pte_base,vaddr);
                  kl_trace4(0,"pte_val: %"FMTPTR"x\n", pte_val);
                  if(KL_ERROR){
                        kl_trace3(0, "Could not read page table entry "
                                "(PAE) for vaddr=%"FMTPTR"x\n",
                                vaddr);
                        return 0;
                  }
                  if(kl_pte_none_i386(pte_val)){
                        KL_ERROR = KLE_INVALID_MAPPING;
                        kl_trace3(0, "invalid page table entry (PAE) "
                                "for vaddr=%"FMTPTR"x\n", vaddr);
                        return 0;
                  }
                  if(!kl_pte_present_i386(pte_val)){
                        KL_ERROR = KLE_PAGE_NOT_PRESENT;
                        kl_trace3(0, "page not present (PAE) "
                                "for vaddr=%"FMTPTR"x\n", vaddr);
                        return (0);
                  }

                  paddr = (pte_val & KL_PAGE_BASE_MASK_I386) | 
                        (vaddr & (~(KL_PAGE_MASK_I386)));
            }
      } else { /* if(KL_KERNEL_FLAGS & KL_IS_PAE_I386){ */
            /* check for use of page size extension, i.e. 4MB page */
            if(pmd_base & KL_PAGE_PSE_I386) {
                  if (kl_pte_none_i386(pmd_base)){
                        KL_ERROR = KLE_INVALID_MAPPING;
                        kl_trace3(0, "invalid page table entry (PSE) "
                                "for vaddr=%"FMTPTR"x\n", vaddr);

                        return(0);
                  }
                  if (!kl_pte_present_i386(pmd_base)){
                        KL_ERROR = KLE_PAGE_NOT_PRESENT;
                        kl_trace3(0, "page not present (PSE) "
                                "for vaddr=%"FMTPTR"x\n", vaddr);

                        return(0);
                  }

                  paddr = (pmd_base & KL_PSE_PAGE_MASK_I386) | 
                        (vaddr & KL_PSE_OFFSET_MASK_I386);
            } else {
                  if (kl_pmd_bad_i386(pmd_base) ||
                      kl_pmd_none_i386(pmd_base)) {
                        KL_ERROR = KLE_INVALID_MAPPING;
                        kl_trace3(0, "invalid pgd entry "
                                "for vaddr=%"FMTPTR"x\n", vaddr);
                        return(0);
                  }
                  /* get the pte 
                   * only 2-level paging, use pmd_base as pte_base */
                  pte_base = pmd_base & KL_PT_BASE_MASK_I386;
                  pte_val = _kl_pte_offset_i386(pte_base,vaddr);
                  kl_trace4(0,"pte_val: %"FMTPTR"x\n", pte_val);
                  if(KL_ERROR){
                        KL_ERROR = KLE_INVALID_MAPPING;
                        kl_trace3(0, "Could not read page table entry "
                                "for vaddr=%"FMTPTR"x\n", vaddr);
                        return 0;
                  }
                  if(kl_pte_none_i386(pte_val)){
                        KL_ERROR = KLE_INVALID_MAPPING;
                        kl_trace3(0, "invalid page table entry "
                                "for vaddr=%"FMTPTR"x\n", vaddr);
                        return 0;
                  }
                  if(!kl_pte_present_i386(pte_val)){
                        KL_ERROR = KLE_PAGE_NOT_PRESENT;
                        kl_trace3(0, "page not present "
                                "for vaddr=%"FMTPTR"x\n", vaddr);
                        return (0);
                  }

                  paddr = (pte_val & KL_PAGE_BASE_MASK_I386) | 
                        (vaddr & (~(KL_PAGE_MASK_I386)));
            }
      }

      return(paddr);
}

Generated by  Doxygen 1.6.0   Back to index