4
* Created by: Michael Holzheu (holzheu@de.ibm.com)
5
* Copyright IBM Corp. 2010
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 (version 2 of the License).
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
#include "makedumpfile.h"
25
#define TABLE_SIZE 4096
28
* Bits in the virtual address
30
* |<----- RX ---------->|
31
* | RFX | RSX | RTX | SX | PX | BX |
35
* RFX: Region first index
36
* RSX: Region second index
37
* RTX: Region third index
42
* RX part of vaddr is divided into three fields RFX, RSX and RTX each of
45
#define _REGION_INDEX_SHIFT 11
46
#define _PAGE_INDEX_MASK 0xff000UL /* page index (PX) mask */
47
#define _BYTE_INDEX_MASK 0x00fffUL /* Byte index (BX) mask */
48
#define _PAGE_BYTE_INDEX_MASK (_PAGE_INDEX_MASK | _BYTE_INDEX_MASK)
50
/* Region/segment table index */
51
#define rsg_index(x, y) \
52
(((x) >> ((_REGION_INDEX_SHIFT * y) + _SEGMENT_INDEX_SHIFT)) \
53
& _REGION_OFFSET_MASK)
54
/* Page table index */
55
#define pte_index(x) (((x) >> _PAGE_INDEX_SHIFT) & _PAGE_OFFSET_MASK)
57
#define rsg_offset(x, y) (rsg_index( x, y) * sizeof(unsigned long))
58
#define pte_offset(x) (pte_index(x) * sizeof(unsigned long))
61
get_machdep_info_s390x(void)
63
unsigned long vmlist, vmalloc_start;
65
info->section_size_bits = _SECTION_SIZE_BITS;
66
info->max_physmem_bits = _MAX_PHYSMEM_BITS;
67
info->page_offset = __PAGE_OFFSET;
69
if (SYMBOL(_stext) == NOT_FOUND_SYMBOL) {
70
ERRMSG("Can't get the symbol of _stext.\n");
73
info->kernel_start = SYMBOL(_stext);
74
DEBUG_MSG("kernel_start : %lx\n", info->kernel_start);
77
* For the compatibility, makedumpfile should run without the symbol
78
* vmlist and the offset of vm_struct.addr if they are not necessary.
80
if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL)
81
|| (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) {
84
if (!readmem(VADDR, SYMBOL(vmlist), &vmlist, sizeof(vmlist))) {
85
ERRMSG("Can't get vmlist.\n");
88
if (!readmem(VADDR, vmlist + OFFSET(vm_struct.addr), &vmalloc_start,
89
sizeof(vmalloc_start))) {
90
ERRMSG("Can't get vmalloc_start.\n");
93
info->vmalloc_start = vmalloc_start;
94
DEBUG_MSG("vmalloc_start: %lx\n", vmalloc_start);
100
is_vmalloc_addr_s390x(unsigned long vaddr)
102
return (info->vmalloc_start && vaddr >= info->vmalloc_start);
106
rsg_table_entry_bad(unsigned long entry, int level)
108
unsigned long mask = ~_REGION_ENTRY_INVALID
109
& ~_REGION_ENTRY_TYPE_MASK
110
& ~_REGION_ENTRY_LENGTH;
113
mask &= ~_REGION_ENTRY_ORIGIN;
115
mask &= ~_SEGMENT_ENTRY_ORIGIN;
117
return (entry & mask) != 0;
120
/* Region or segment table traversal function */
122
_kl_rsg_table_deref_s390x(unsigned long vaddr, unsigned long table,
125
unsigned long offset, entry;
127
offset = rsg_offset(vaddr, level);
129
/* check if offset is over the table limit. */
130
if (offset >= ((len + 1) * TABLE_SIZE)) {
131
ERRMSG("offset is over the table limit.\n");
135
if (!readmem(VADDR, table + offset, &entry, sizeof(entry))) {
137
ERRMSG("Can't read region table %d entry\n", level);
139
ERRMSG("Can't read segment table entry\n");
143
* Check if the segment table entry could be read and doesn't have
144
* any of the reserved bits set.
146
if (rsg_table_entry_bad(entry, level)) {
147
ERRMSG("Bad region/segment table entry.\n");
151
* Check if the region/segment table entry is with valid
152
* level and not invalid.
154
if ((RSG_TABLE_LEVEL(entry) != level)
155
&& (entry & _REGION_ENTRY_INVALID)) {
156
ERRMSG("Invalid region/segment table level or entry.\n");
163
/* Page table traversal function */
164
static ulong _kl_pg_table_deref_s390x(unsigned long vaddr, unsigned long table)
166
unsigned long offset, entry;
168
offset = pte_offset(vaddr);
169
readmem(VADDR, table + offset, &entry, sizeof(entry));
171
* Check if the page table entry could be read and doesn't have
172
* any of the reserved bits set.
173
* Check if the page table entry has the invalid bit set.
175
if (entry & (_PAGE_CO | _PAGE_ZERO | _PAGE_INVALID)) {
176
ERRMSG("Invalid page table entry.\n");
183
/* vtop_s390x() - translate virtual address to physical
184
* @vaddr: virtual address to translate
186
* Function converts the @vaddr into physical address using page tables.
189
* Physical address or NOT_PADDR if translation fails.
191
static unsigned long long
192
vtop_s390x(unsigned long vaddr)
194
unsigned long long paddr = NOT_PADDR;
195
unsigned long table, entry;
198
if (SYMBOL(swapper_pg_dir) == NOT_FOUND_SYMBOL) {
199
ERRMSG("Can't get the symbol of swapper_pg_dir.\n");
202
table = SYMBOL(swapper_pg_dir);
204
/* Read the first entry to find the number of page table levels. */
205
readmem(VADDR, table, &entry, sizeof(entry));
206
level = TABLE_LEVEL(entry);
207
len = TABLE_LENGTH(entry);
209
if ((vaddr >> (_SEGMENT_PAGE_SHIFT + (_REGION_INDEX_SHIFT * level)))) {
210
ERRMSG("Address too big for the number of page table " \
216
* Walk the region and segment tables.
219
entry = _kl_rsg_table_deref_s390x(vaddr, table, len, level);
223
table = entry & _REGION_ENTRY_ORIGIN;
224
len = RSG_TABLE_LENGTH(entry);
229
* Check if this is a large page.
230
* if yes, then add the 1MB page offset (PX + BX) and return the value.
231
* if no, then get the page table entry using PX index.
233
if (entry & _SEGMENT_ENTRY_LARGE) {
234
paddr = table + (vaddr & _PAGE_BYTE_INDEX_MASK);
236
entry = _kl_pg_table_deref_s390x(vaddr,
237
entry & _SEGMENT_ENTRY_ORIGIN);
242
* Isolate the page origin from the page table entry.
243
* Add the page offset (BX).
245
paddr = (entry & _REGION_ENTRY_ORIGIN)
246
+ (vaddr & _BYTE_INDEX_MASK);
253
vaddr_to_paddr_s390x(unsigned long vaddr)
255
unsigned long long paddr;
257
paddr = vaddr_to_paddr_general(vaddr);
258
if (paddr != NOT_PADDR)
261
if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL)
262
|| (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) {
263
ERRMSG("Can't get necessary information for vmalloc "
268
if (is_vmalloc_addr_s390x(vaddr)) {
269
paddr = vtop_s390x(vaddr);
272
ERRMSG("Can't convert a virtual address(%lx) to " \
273
"physical address.\n", vaddr);
280
#endif /* __s390x__ */