~ubuntu-branches/ubuntu/wily/makedumpfile/wily

« back to all changes in this revision

Viewing changes to arm.c

  • Committer: Bazaar Package Importer
  • Author(s): John Wright
  • Date: 2011-04-26 20:05:16 UTC
  • mfrom: (1.1.4 upstream) (7.1.4 sid)
  • Revision ID: james.westby@ubuntu.com-20110426200516-7dzi6nnzouzfto2f
* Cherry-pick upstream commits:
  - [PATCH] BUGFIX: Avoid SIGSEGV when specifying -V option.
    (5b8c2da75cbdb230019a3b956793fb768055b977)
  - [PATCH] Copy correct nr_cpus info to dumpfile during re-filtering.
    (c4f1c98a9827c1c0e41772c1954940fbf1b48048)
* kdump-tools.init: Don't exit with failure status except for bad
  usage.  This way, even if /etc/default/kdump-tools has USE_KDUMP=1
  but the kernel command line or debug kernels are not set up,
  installation of a new version of the package will not leave it
  unconfigured.  (Closes: #623470)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * arm.c
 
3
 *
 
4
 * Created by: Mika Westerberg <ext-mika.1.westerberg@nokia.com>
 
5
 * Copyright (C) 2010 Nokia Corporation
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 */
 
17
#ifdef __arm__
 
18
 
 
19
#include "makedumpfile.h"
 
20
 
 
21
#define PMD_TYPE_MASK   3
 
22
#define PMD_TYPE_SECT   2
 
23
#define PMD_TYPE_TABLE  1
 
24
 
 
25
#define pgd_index(vaddr) ((vaddr) >> PGDIR_SHIFT)
 
26
#define pte_index(vaddr) ((vaddr >> PAGESHIFT()) & (PTRS_PER_PTE - 1))
 
27
 
 
28
#define pgd_offset(pgdir, vaddr) \
 
29
        ((pgdir) + pgd_index(vaddr) * 2 * sizeof(unsigned long))
 
30
#define pmd_offset(dir, vaddr) (dir)
 
31
#define pte_offset(pmd, vaddr) \
 
32
        (pmd_page_vaddr(pmd) + pte_index(vaddr) * sizeof(unsigned long))
 
33
 
 
34
/*
 
35
 * These only work for kernel directly mapped addresses.
 
36
 */
 
37
#define __va(paddr) ((paddr) - info->phys_base + info->page_offset)
 
38
#define __pa(vaddr) ((vaddr) - info->page_offset + info->phys_base)
 
39
 
 
40
static inline unsigned long
 
41
pmd_page_vaddr(unsigned long pmd)
 
42
{
 
43
        unsigned long ptr;
 
44
 
 
45
        ptr = pmd & ~(PTRS_PER_PTE * sizeof(void *) - 1);
 
46
        ptr += PTRS_PER_PTE * sizeof(void *);
 
47
 
 
48
        return __va(ptr);
 
49
}
 
50
 
 
51
int
 
52
get_phys_base_arm(void)
 
53
{
 
54
        unsigned long phys_base = ULONG_MAX;
 
55
        int i;
 
56
 
 
57
        /*
 
58
         * We resolve phys_base from PT_LOAD segments. LMA contains physical
 
59
         * address of the segment, and we use the first one.
 
60
         */
 
61
        for (i = 0; i < info->num_load_memory; i++) {
 
62
                const struct pt_load_segment *pls = &info->pt_load_segments[i];
 
63
 
 
64
                if (pls->phys_start < phys_base)
 
65
                        phys_base = pls->phys_start;
 
66
        }
 
67
 
 
68
        if (phys_base == ULONG_MAX) {
 
69
                ERRMSG("Can't determine phys_base.\n");
 
70
                return FALSE;
 
71
        }
 
72
 
 
73
        info->phys_base = phys_base;
 
74
        DEBUG_MSG("phys_base    : %lx\n", phys_base);
 
75
 
 
76
        return TRUE;
 
77
}
 
78
 
 
79
int
 
80
get_machdep_info_arm(void)
 
81
{
 
82
        info->page_offset = SYMBOL(_stext) & 0xffff0000UL;
 
83
        info->max_physmem_bits = _MAX_PHYSMEM_BITS;
 
84
        info->kernel_start = SYMBOL(_stext);
 
85
        info->section_size_bits = _SECTION_SIZE_BITS;
 
86
 
 
87
        DEBUG_MSG("page_offset  : %lx\n", info->page_offset);
 
88
        DEBUG_MSG("kernel_start : %lx\n", info->kernel_start);
 
89
 
 
90
        return TRUE;
 
91
}
 
92
 
 
93
/*
 
94
 * vtop_arm() - translate arbitrary virtual address to physical
 
95
 * @vaddr: virtual address to translate
 
96
 *
 
97
 * Function translates @vaddr into physical address using page tables. This
 
98
 * address can be any virtual address. Returns physical address of the
 
99
 * corresponding virtual address or %NOT_PADDR when there is no translation.
 
100
 */
 
101
static unsigned long long
 
102
vtop_arm(unsigned long vaddr)
 
103
{
 
104
        unsigned long long paddr = NOT_PADDR;
 
105
        unsigned long ptr, pgd, pte, pmd;
 
106
 
 
107
        if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) {
 
108
                ERRMSG("Can't get the symbol of swapper_pg_dir.\n");
 
109
                return NOT_PADDR;
 
110
        }
 
111
 
 
112
        ptr = pgd_offset(SYMBOL(swapper_pg_dir), vaddr);
 
113
        if (!readmem(VADDR, ptr, &pgd, sizeof(pmd))) {
 
114
                ERRMSG("Can't read pgd\n");
 
115
                return NOT_PADDR;
 
116
        }
 
117
 
 
118
        if (info->vaddr_for_vtop == vaddr)
 
119
                MSG("  PGD : %08lx => %08lx\n", ptr, pgd);
 
120
 
 
121
        pmd = pmd_offset(pgd, vaddr);
 
122
 
 
123
        switch (pmd & PMD_TYPE_MASK) {
 
124
        case PMD_TYPE_TABLE: {
 
125
                /* 4k small page */
 
126
                ptr = pte_offset(pmd, vaddr);
 
127
                if (!readmem(VADDR, ptr, &pte, sizeof(pte))) {
 
128
                        ERRMSG("Can't read pte\n");
 
129
                        return NOT_PADDR;
 
130
                }
 
131
 
 
132
                if (info->vaddr_for_vtop == vaddr)
 
133
                        MSG("  PTE : %08lx => %08lx\n", ptr, pte);
 
134
 
 
135
                if (!(pte & _PAGE_PRESENT)) {
 
136
                        ERRMSG("Can't get a valid pte.\n");
 
137
                        return NOT_PADDR;
 
138
                }
 
139
 
 
140
                paddr = PAGEBASE(pte) + (vaddr & (PAGESIZE() - 1));
 
141
                break;
 
142
        }
 
143
 
 
144
        case PMD_TYPE_SECT:
 
145
                /* 1MB section */
 
146
                pte = pmd & PMD_MASK;
 
147
                paddr = pte + (vaddr & (PMD_SIZE - 1));
 
148
                break;
 
149
        }
 
150
 
 
151
        return paddr;
 
152
}
 
153
 
 
154
unsigned long long
 
155
vaddr_to_paddr_arm(unsigned long vaddr)
 
156
{
 
157
        /*
 
158
         * Only use translation tables when user has explicitly requested us to
 
159
         * perform translation for a given address. Otherwise we assume that the
 
160
         * translation is done within the kernel direct mapped region.
 
161
         */
 
162
        if (info->vaddr_for_vtop == vaddr)
 
163
                return vtop_arm(vaddr);
 
164
 
 
165
        return __pa(vaddr);
 
166
}
 
167
 
 
168
#endif /* __arm__ */