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

kl_kern_arm.c

/*
 * This file is part of libklib.
 * A library which provides access to Linux system kernel dumps.
 * This file handles the architecture-dependent parts KLIB for 
 * ARM/XScale based systems.
 *
 * Ported from kl_kern_i386.c
 * by Fleming Feng(fleming.feng@intel.com)
 * 
 * Copyright 1999 Silicon Graphics, Inc. All rights reserved.
 * Copyright (C) 2003, Intel Corp. All rights reserved.
 *
 * 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>

/* 
 * kl_kernelstack_arm()
 */
kaddr_t
kl_kernelstack_arm(kaddr_t task)
{
      kaddr_t saddr = 0, thread_info;
      void *tsp;

      if ((tsp = kl_alloc_block(TASK_STRUCT_SZ, K_TEMP))) {
            kl_get_task_struct(task, 2, tsp);
            if (!KL_ERROR) {
                  if(LINUX_2_6_X(KL_LINUX_RELEASE)){
                        thread_info = kl_kaddr(tsp, "task_struct",
                                           "thread_info");
                        saddr = thread_info + KL_KSTACK_SIZE_ARM;
                  } else{
                        saddr = (task + KL_KSTACK_SIZE_ARM);
                  }
            }
            kl_free_block(tsp);
      }
      return(saddr);
} 

/*
 * Name: kl_vtop_arm()
 * Func: Performs simple virtual to physical address translation
 *       without checking mmap memory for ARM/XScale system.
 *
 */
int
kl_vtop_arm(kaddr_t vaddr, kaddr_t* paddr)
{
      if(KL_KADDR_IS_PHYSICAL(vaddr)){
            /* Linux Kernel Address */
            *paddr = (vaddr - KL_PAGE_OFFSET + kl_start_physaddr);
      }
      else{
            /* Address from mmap */
            *paddr = vaddr;
      }
      return(0);
}

kaddr_t
kl_fix_vaddr_arm(kaddr_t vaddr, size_t sz)
{
      kl_dump_header_arm_t* dha = NULL;
      kaddr_t addr;
      int i;

      dha = (kl_dump_header_arm_t*)kl_alloc_block(sizeof(kl_dump_header_arm_t), 
                                        K_TEMP);
      if(dha == NULL){
            KL_ERROR = KLE_NO_MEMORY;
            return ((kaddr_t)NULL);
      }
      memset(dha, 0, sizeof(kl_dump_header_arm_t));

      if (kl_get_dump_header_arm(dha)){
            kl_free_block(dha);
            return vaddr;
      }

      /* this is a very simplistic check to see if we have saved 
       * (snapshotted) this particular block. This is very limited 
       * to finding the saved task structs only.
       */
      for(i = 0; i < KL_GET_UINT32(&(dha->smp_num_cpus)); i++){
            if(KL_GET_UINT32(&(dha->smp_regs[i].dha_ARM_regs.ARM_pc)) < KL_PAGE_OFFSET){
                  /* if task is in user space, 
                     no need to look at saved stack */
                  continue;
            }
            if(LINUX_2_6_X(KL_LINUX_RELEASE))
                  addr = KL_GET_PTR(&(dha->stack_ptr[i]));
            else
                  addr = KL_GET_PTR(&(dha->smp_current_task[i]));
            if (vaddr >= addr && vaddr + sz <  addr + KL_KSTACK_SIZE_ARM){
                  vaddr = (kaddr_t)(KL_GET_UINT32(&dha->stack[i]) + 
                                (vaddr - addr));
                  kl_free_block(dha);
                  break;
            }
      }
      return vaddr;
}

/*
 * Name: kl_init_virtop_arm()
 * Func: initialize virtual to physical address translation
 *       This function must at least initialize high_memory and init_mm.
 */
int
kl_init_virtop_arm(void)
{
      syment_t *sp;

      kl_start_physaddr = kl_get_start_physaddr();
      if(kl_start_physaddr == 0xffffffff)
            return(1);
      
      if(!(sp = kl_lkup_symname("high_memory"))){
            /* XXX set error code */
            return(1);
      } else {
            /* Read (void *) high_memory from dump.
               We need to make sure that the address is not virtually
               mapped kernel data. We have to do this by hand since
               we haven't got virtop mechanism working yet...
            */
            KL_HIGH_MEMORY = KL_READ_PTR(sp->s_addr - KL_PAGE_OFFSET +
                                   kl_start_physaddr);
            if (KL_ERROR) {
                  KL_HIGH_MEMORY = (kaddr_t) -1;
                  /* XXX set error code */
                  return(1);
            }
      }

      /* if high_memory not set, we assume all addresses above PAGE_OFFSET
       * to be physical ones (see macro KL_KADDR_IS_PHYSICAL in kl_mem.h)
       */
      if(!KL_HIGH_MEMORY){
            KL_HIGH_MEMORY = (kaddr_t) -1;
      }

      /* Get the address of init_mm and convert it to a physical address
       * so that we can make direct calls to kl_readmem(). We make a call
       * to kl_vtop() since we have not finished setting up for calls to
       * kl_virtop().
       */
        if (!(sp = kl_lkup_symname("init_mm"))) {
            /* XXX set error code */
                return(1);
      } else {
            KL_INIT_MM = sp->s_addr - KL_PAGE_OFFSET + kl_start_physaddr;
      }

      sp = kl_lkup_symname("num_physpages");
      if(!sp){
            /* XXX set error code */
            return(1);
      }
      /* unsigned long num_physpages */
      NUM_PHYSPAGES = KL_READ_PTR(sp->s_addr - KL_PAGE_OFFSET + kl_start_physaddr);
      if (KL_ERROR) {
            /* XXX set error code */
            return(1);
      }

      /* Get the start address of the kernel page table
       */
      if (!(sp = kl_lkup_symname("mem_map"))) {
            /* XXX set error code */
            return(1);
      } else {
            /* mem_map_t * mem_map */
            MEM_MAP = KL_READ_PTR(sp->s_addr - KL_PAGE_OFFSET + kl_start_physaddr);
            if (KL_ERROR) {
                  /* XXX set error code */
                  return(1);
            }
      }

      return(0);
}

/*
 * kl_virtop_arm()
 *
 *   Translate a virtual address into a physical address. 
 */
int
kl_virtop_arm(kaddr_t vaddr, void *m, kaddr_t *paddr)
{
      int mm_alloced = 0;
      void *mmp = m;

      *paddr = (kaddr_t) NULL;

      kl_reset_error();

      if (KL_KADDR_IS_PHYSICAL(vaddr)) {
            *paddr = (vaddr - KL_PAGE_OFFSET + kl_start_physaddr);
      } else if (mmp || KL_INIT_MM) {
            /* Treat address as logical and map to a physical one */
            if (!mmp) {
                  if((mmp = kl_alloc_block(MM_STRUCT_SZ, K_TEMP))) {
                        kl_readmem(KL_INIT_MM, MM_STRUCT_SZ, mmp);
                        if (KL_ERROR) {
                              kl_free_block(mmp);
                              mmp = NULL;
                        } else {
                              mm_alloced++;
                        }
                  }
            }
            if (mmp) {
                  *paddr = KL_MMAP_VIRTOP(vaddr, mmp);
                  if(KL_ERROR){
                        KL_ERROR = KLE_INVALID_MAPPING;
                  }
            }
      } else {
            /* Treat as a physical address but make sure
             * the address does not exceed maximum physical
             * memory.
             */
            if(vaddr > KL_PAGE_OFFSET){
                  vaddr -= KL_PAGE_OFFSET;
            }
            if ((vaddr >> KL_PAGE_SHIFT) < NUM_PHYSPAGES) {
                  *paddr = vaddr;
            } else {
                  KL_ERROR = KLE_INVALID_PADDR;
            }
      }

      if (mm_alloced) {
            kl_free_block(mmp);
      }     

      if(KL_ERROR){
            *paddr = (kaddr_t) NULL;
            return(1);
      } else {
            return(0);
      }
}

Generated by  Doxygen 1.6.0   Back to index