2 * Implements the routines which handle the format specific
3 * aspects of dump for the default dump format.
5 * Used in single stage dumping and stage 1 of soft-boot based dumping
6 * Saves data in LKCD (lcrash) format
8 * Previously a part of dump_base.c
10 * Started: Oct 2002 - Suparna Bhattacharya <suparna@in.ibm.com>
11 * Split off and reshuffled LKCD dump format code around generic
12 * dump method interfaces.
14 * Derived from original code created by
15 * Matt Robinson <yakker@sourceforge.net>)
17 * Contributions from SGI, IBM, HP, MCL, and others.
19 * Copyright (C) 1999 - 2002 Silicon Graphics, Inc. All rights reserved.
20 * Copyright (C) 2000 - 2002 TurboLinux, Inc. All rights reserved.
21 * Copyright (C) 2001 - 2002 Matt D. Robinson. All rights reserved.
22 * Copyright (C) 2002 International Business Machines Corp.
24 * This code is released under version 2 of the GNU GPL.
27 #include <linux/types.h>
28 #include <linux/kernel.h>
29 #include <linux/time.h>
30 #include <linux/sched.h>
31 #include <linux/ptrace.h>
32 #include <linux/utsname.h>
33 #include <linux/dump.h>
35 #include "dump_methods.h"
41 * System dumps are currently the combination of a dump header and a set
42 * of data pages which contain the system memory. The layout of the dump
43 * (for full dumps) is as follows:
45 * +-----------------------------+
46 * | generic dump header |
47 * +-----------------------------+
48 * | architecture dump header |
49 * +-----------------------------+
51 * +-----------------------------+
53 * +-----------------------------+
55 * +-----------------------------+
57 * +-----------------------------+
63 * +-----------------------------+
65 * +-----------------------------+
67 * There are two dump headers, the first which is architecture
68 * independent, and the other which is architecture dependent. This
69 * allows different architectures to dump different data structures
70 * which are specific to their chipset, CPU, etc.
72 * After the dump headers come a succession of dump page headers along
73 * with dump pages. The page header contains information about the page
74 * size, any flags associated with the page (whether it's compressed or
75 * not), and the address of the page. After the page header is the page
76 * data, which is either compressed (or not). Each page of data is
77 * dumped in succession, until the final dump header (PAGE_END) is
78 * placed at the end of the dump, assuming the dump device isn't out
81 * This mechanism allows for multiple compression types, different
82 * types of data structures, different page ordering, etc., etc., etc.
83 * It's a very straightforward mechanism for dumping system memory.
86 struct __dump_header dump_header; /* the primary dump header */
87 struct __dump_header_asm dump_header_asm; /* the arch-specific dump header */
90 * Set up common header fields (mainly the arch indep section)
91 * Per-cpu state is handled by lcrash_save_context
92 * Returns the size of the header in bytes.
94 static int lcrash_init_dump_header(const char *panic_str)
96 struct timeval dh_time;
97 u64 temp_memsz = dump_header.dh_memory_size;
99 /* make sure the dump header isn't TOO big */
100 if ((sizeof(struct __dump_header) +
101 sizeof(struct __dump_header_asm)) > DUMP_BUFFER_SIZE) {
102 printk("LKCD: combined "
103 "headers larger than DUMP_BUFFER_SIZE!\n");
107 /* initialize the dump headers to zero */
108 /* save dha_stack pointer because it may contains pointer for stack! */
109 memset(&dump_header, 0, sizeof(dump_header));
110 memset(&dump_header_asm, 0,
111 offsetof(struct __dump_header_asm, dha_stack));
112 memset(&dump_header_asm.dha_stack+1, 0,
113 sizeof(dump_header_asm) -
114 offsetof(struct __dump_header_asm, dha_stack) -
115 sizeof(dump_header_asm.dha_stack));
116 dump_header.dh_memory_size = temp_memsz;
118 /* configure dump header values */
119 dump_header.dh_magic_number = DUMP_MAGIC_NUMBER;
120 dump_header.dh_version = DUMP_VERSION_NUMBER;
121 dump_header.dh_memory_start = PAGE_OFFSET;
122 dump_header.dh_memory_end = DUMP_MAGIC_NUMBER;
123 dump_header.dh_header_size = sizeof(struct __dump_header);
124 dump_header.dh_page_size = PAGE_SIZE;
125 dump_header.dh_dump_level = dump_config.level;
126 dump_header.dh_current_task = (unsigned long) current;
127 dump_header.dh_dump_compress = dump_config.dumper->compress->
129 dump_header.dh_dump_polling = dump_config.polling;
130 dump_header.dh_dump_device = dump_config.dumper->dev->device_id;
131 dump_header.dh_dump_buffer_size = DUMP_BUFFER_SIZE;
134 dump_header.dh_num_bytes = 0;
136 dump_header.dh_num_dump_pages = 0;
137 do_gettimeofday(&dh_time);
138 dump_header.dh_time.tv_sec = dh_time.tv_sec;
139 dump_header.dh_time.tv_usec = dh_time.tv_usec;
141 memcpy((void *)&(dump_header.dh_utsname_sysname),
142 (const void *)&(system_utsname.sysname), __NEW_UTS_LEN + 1);
143 memcpy((void *)&(dump_header.dh_utsname_nodename),
144 (const void *)&(system_utsname.nodename), __NEW_UTS_LEN + 1);
145 memcpy((void *)&(dump_header.dh_utsname_release),
146 (const void *)&(system_utsname.release), __NEW_UTS_LEN + 1);
147 memcpy((void *)&(dump_header.dh_utsname_version),
148 (const void *)&(system_utsname.version), __NEW_UTS_LEN + 1);
149 memcpy((void *)&(dump_header.dh_utsname_machine),
150 (const void *)&(system_utsname.machine), __NEW_UTS_LEN + 1);
151 memcpy((void *)&(dump_header.dh_utsname_domainname),
152 (const void *)&(system_utsname.domainname), __NEW_UTS_LEN + 1);
155 memcpy((void *)&(dump_header.dh_panic_string),
156 (const void *)panic_str, DUMP_PANIC_LEN);
159 dump_header_asm.dha_magic_number = DUMP_ASM_MAGIC_NUMBER;
160 dump_header_asm.dha_version = DUMP_ASM_VERSION_NUMBER;
161 dump_header_asm.dha_header_size = sizeof(dump_header_asm);
163 dump_header_asm.dha_smp_num_cpus = num_online_cpus();
164 printk("LKCD: smp_num_cpus in header %d\n",
165 dump_header_asm.dha_smp_num_cpus);
167 dump_header_asm.dha_dumping_cpu = smp_processor_id();
169 return sizeof(dump_header) + sizeof(dump_header_asm);
173 int dump_lcrash_configure_header(const char *panic_str,
174 const struct pt_regs *regs)
178 dump_config.dumper->header_len = lcrash_init_dump_header(panic_str);
180 /* capture register states for all processors */
181 dump_save_this_cpu(regs);
182 __dump_save_other_cpus(); /* side effect:silence cpus */
184 /* configure architecture-specific dump header values */
185 if ((retval = __dump_configure_header(regs)))
188 dump_config.dumper->header_dirty++;
191 /* save register and task context */
192 void dump_lcrash_save_context(int cpu, const struct pt_regs *regs,
193 struct task_struct *tsk)
195 /* This level of abstraction might be redundantly redundant */
196 __dump_save_context(cpu, regs, tsk);
199 /* write out the header */
200 int dump_write_header(void)
202 int retval = 0, size;
203 void *buf = dump_config.dumper->dump_buf;
205 /* accounts for DUMP_HEADER_OFFSET if applicable */
206 if ((retval = dump_dev_seek(0))) {
207 printk("LKCD: Unable to seek to dump header offset: %d\n",
212 memcpy(buf, (void *)&dump_header, sizeof(dump_header));
213 size = sizeof(dump_header);
214 memcpy(buf + size, (void *)&dump_header_asm, sizeof(dump_header_asm));
215 size += sizeof(dump_header_asm);
216 size = PAGE_ALIGN(size);
217 retval = dump_ll_write(buf , size);
220 return (retval >= 0) ? ENOSPC : retval;
224 int dump_generic_update_header(void)
228 if (dump_config.dumper->header_dirty) {
229 if ((err = dump_write_header())) {
230 printk("LKCD: dump write header failed !err %d\n", err);
232 dump_config.dumper->header_dirty = 0;
239 static inline int is_curr_stack_page(struct page *page, unsigned long size)
241 unsigned long thread_addr = (unsigned long)current_thread_info();
242 unsigned long addr = (unsigned long)page_address(page);
244 return !PageHighMem(page) && (addr < thread_addr + THREAD_SIZE)
245 && (addr + size > thread_addr);
248 static inline int is_dump_page(struct page *page, unsigned long size)
250 unsigned long addr = (unsigned long)page_address(page);
251 unsigned long dump_buf = (unsigned long)dump_config.dumper->dump_buf;
253 return !PageHighMem(page) && (addr < dump_buf + DUMP_BUFFER_SIZE)
254 && (addr + size > dump_buf);
257 int dump_allow_compress(struct page *page, unsigned long size)
260 * Don't compress the page if any part of it overlaps
261 * with the current stack or dump buffer (since the contents
262 * in these could be changing while compression is going on)
264 return !is_curr_stack_page(page, size) && !is_dump_page(page, size);
267 void lcrash_init_pageheader(struct __dump_page *dp, struct page *page,
270 memset(dp, sizeof(struct __dump_page), 0);
274 dp->dp_address = (loff_t)page_to_pfn(page) << PAGE_SHIFT;
277 dp->dp_page_index = dump_header.dh_num_dump_pages;
278 dp->dp_byte_offset = dump_header.dh_num_bytes + DUMP_BUFFER_SIZE
279 + DUMP_HEADER_OFFSET; /* ?? */
280 #endif /* DUMP_DEBUG */
283 int dump_lcrash_add_data(unsigned long loc, unsigned long len)
285 struct page *page = (struct page *)loc;
286 void *addr, *buf = dump_config.dumper->curr_buf;
287 struct __dump_page *dp = (struct __dump_page *)buf;
290 if (buf > dump_config.dumper->dump_buf + DUMP_BUFFER_SIZE)
293 lcrash_init_pageheader(dp, page, len);
294 buf += sizeof(struct __dump_page);
297 addr = kmap_atomic(page, KM_DUMP);
298 size = bytes = (len > PAGE_SIZE) ? PAGE_SIZE : len;
299 /* check for compression */
300 if (dump_allow_compress(page, bytes)) {
301 size = dump_compress_data((char *)addr, bytes,
304 /* set the compressed flag if the page did compress */
305 if (size && (size < bytes)) {
306 dp->dp_flags |= DUMP_DH_COMPRESSED;
308 /* compression failed -- default to raw mode */
309 dp->dp_flags |= DUMP_DH_RAW;
310 memcpy(buf, addr, bytes);
313 /* memset(buf, 'A', size); temporary: testing only !! */
314 kunmap_atomic(addr, KM_DUMP);
321 /* now update the header */
323 dump_header.dh_num_bytes += dp->dp_size + sizeof(*dp);
325 dump_header.dh_num_dump_pages++;
326 dump_config.dumper->header_dirty++;
328 dump_config.dumper->curr_buf = buf;
333 int dump_lcrash_update_end_marker(void)
335 struct __dump_page *dp =
336 (struct __dump_page *)dump_config.dumper->curr_buf;
340 lcrash_init_pageheader(dp, NULL, 0);
341 dp->dp_flags |= DUMP_DH_END; /* tbd: truncation test ? */
343 /* now update the header */
345 dump_header.dh_num_bytes += sizeof(*dp);
347 dump_config.dumper->curr_buf += sizeof(*dp);
348 left = dump_config.dumper->curr_buf - dump_config.dumper->dump_buf;
353 if ((ret = dump_dev_seek(dump_config.dumper->curr_offset))) {
354 printk("LKCD: Seek failed at offset 0x%llx\n",
355 dump_config.dumper->curr_offset);
359 if (DUMP_BUFFER_SIZE > left)
360 memset(dump_config.dumper->curr_buf, 'm',
361 DUMP_BUFFER_SIZE - left);
363 if ((ret = dump_ll_write(dump_config.dumper->dump_buf,
364 DUMP_BUFFER_SIZE)) < DUMP_BUFFER_SIZE) {
365 return (ret < 0) ? ret : -ENOSPC;
368 dump_config.dumper->curr_offset += DUMP_BUFFER_SIZE;
370 if (left > DUMP_BUFFER_SIZE) {
371 left -= DUMP_BUFFER_SIZE;
372 memcpy(dump_config.dumper->dump_buf,
373 dump_config.dumper->dump_buf + DUMP_BUFFER_SIZE, left);
374 dump_config.dumper->curr_buf -= DUMP_BUFFER_SIZE;
383 /* Default Formatter (lcrash) */
384 struct dump_fmt_ops dump_fmt_lcrash_ops = {
385 .configure_header = dump_lcrash_configure_header,
386 .update_header = dump_generic_update_header,
387 .save_context = dump_lcrash_save_context,
388 .add_data = dump_lcrash_add_data,
389 .update_end_marker = dump_lcrash_update_end_marker
392 struct dump_fmt dump_fmt_lcrash = {
394 .ops = &dump_fmt_lcrash_ops