linux-headers/arch/e2k/include/asm/cnt_point.h

360 lines
9.7 KiB
C

/* $Id: cnt_point.h,v 1.3 2009/06/29 11:51:48 atic Exp $
*
* Recovery the system from control point.
*/
#ifndef _E2K_CNT_POINT_H
#define _E2K_CNT_POINT_H
#include <asm/types.h>
#include <asm/boot_recovery.h>
#include <asm/boot_flags.h>
/*
* Core dump header on the disk
* Total size of header should be one page of memory = one block on disk
* Note that the first kilobyte is reserved for boot loader or
* disk label stuff...
* The following first bytes should contain signature and the last bytes
* of header - magic value to indicate dump header itegrety
* Other structures are aligned to have constant offset in the header
* by adding zip areas in the structure end.
*/
#define TOTAL_DUMP_HEADER_SIZE PAGE_SIZE
#define BOOTBITS_DUMP_HEADER_SIZE 0x400 /* offset 0x000 */
#define DUMP_INFO_HEADER_SIZE 0x100 /* offset 0x400 */
#define CORE_DUMP_HEADER_SIZE 0x500 /* offset 0x500 */
/* offset 0xa00 - gap */
/* offset 0xff8 - magic */
/*
* Dump device and common dump state info
* Dump file space layout:
* block 0 dump file header
* block 1 core dump area start
* ---------------------------------
* | header | core dump area |
* ---------------------------------
* 0 block
* 1 block
*/
#define CORE_DUMP_AREA_OFFSET 1
#define DEFAULT_CORE_AREA_MAX_SIZE (16 * 1024L) /* 16 Gb */
typedef struct dump_desc {
u64 signature; /* signature to indicate dump */
/* header structure start */
/* should be first bytes of useful */
/* part of the header */
u8 cntp_valid; /* control points header of file */
/* is created and valid */
u8 core_valid; /* system core dump header of file */
/* is created and valid */
u64 file_size; /* total size of dump file */
/* in pages */
/* (page size = block size) */
u64 cntp_offset; /* offset (in blocks = page) */
/* of control points area in */
/* the dump file */
u64 cntp_size; /* size of control points area */
/* in blocks */
u64 core_offset; /* offset (in blocks = page) */
/* of core dump area in */
/* the dump file */
u64 core_size; /* size of core dump area */
/* in blocks */
} dump_desc_t;
/*
* System core dump state info
*/
typedef struct core_dump {
} core_dump_t;
/*
* Dump header on the disk structure
*/
typedef struct dump_header {
/* Space for disklabel etc. */
u8 bootbits[BOOTBITS_DUMP_HEADER_SIZE];
dump_desc_t info; /* Device & dump state common info */
u8 zip1[DUMP_INFO_HEADER_SIZE - sizeof (dump_desc_t)];
core_dump_t core; /* System core dump header stuff */
u8 zip3[CORE_DUMP_HEADER_SIZE - sizeof (core_dump_t)];
/* zip area to make size of */
/* header - constant == PAGE_SIZE */
u8 gap[ TOTAL_DUMP_HEADER_SIZE -
BOOTBITS_DUMP_HEADER_SIZE -
DUMP_INFO_HEADER_SIZE -
CORE_DUMP_HEADER_SIZE -
8]; /* u64 : magic */
u64 magic; /* magic value to indicate control */
/* point header structure */
/* should be last bytes of the */
/* header */
} dump_header_t;
#define DUMP_HEADER_SIGNATURE 0xe2c0c0e226143210
#define DUMP_HEADER_MAGIC 0xe2c0c0e22614cdef
#define DUMP_BLOCK_TO_SECTOR(block) ((block) * (PAGE_SIZE >> 9))
#define CORE_BLOCK_TO_SECTOR(block) DUMP_BLOCK_TO_SECTOR(block)
/*
* Forwards of some functions to recover system state
*/
extern struct vm_area_struct *cntp_find_vma(struct task_struct *ts,
unsigned long addr);
extern void dump_prepare(u16 dump_dev, u64 dump_sector);
extern void start_emergency_dump(void);
extern int create_dump_point(void);
extern void init_dump_analyze_mode(void);
extern void start_dump_analyze(void);
extern e2k_addr_t cntp_kernel_address_to_phys(e2k_addr_t address);
extern e2k_addr_t cntp_user_address_to_phys(struct task_struct *tsk,
e2k_addr_t address);
extern int map_memory_region(e2k_addr_t mem_base, e2k_addr_t mem_end,
int *just_mapped_point);
extern int run_init_process(const char *init_filename);
#if defined(CONFIG_EMERGENCY_DUMP)
extern unsigned int nr_swapfiles;
extern struct swap_info_struct *swap_info[MAX_SWAPFILES];
#endif
extern e2k_addr_t cntp_kernel_base;
extern int cur_cnt_point;
extern int cntp_small_kern_mem_div;
extern int dump_analyze_mode;
extern int dump_analyze_opt;
extern char dump_analyze_cmd[];
#define boot_cur_cnt_point \
boot_get_vo_value(cur_cnt_point)
#define boot_cntp_small_kern_mem_div \
boot_get_vo_value(cntp_small_kern_mem_div)
#define boot_dump_analyze_mode \
boot_get_vo_value(dump_analyze_mode)
#define boot_dump_analyze_opt \
boot_get_vo_value(dump_analyze_opt)
#define boot_dump_analyze_cmd \
boot_vp_to_pp((char *)dump_analyze_cmd)
extern inline e2k_size_t
get_dump_analyze_bank_size(e2k_phys_bank_t *phys_bank, int cntp_num)
{
e2k_addr_t base, new_base;
e2k_size_t size, new_size;
BUG_ON(cntp_num == 0 || cntp_num == 1);
size = phys_bank->pages_num * PAGE_SIZE;
base = phys_bank->base_addr;
new_base = LARGE_PAGE_ALIGN_DOWN(base);
new_size = size - (new_base - base);
return LARGE_PAGE_ALIGN_UP(new_size / cntp_num);
}
extern inline e2k_size_t
get_dump_analyze_memory_len(e2k_phys_bank_t *phys_bank, int cntp, int cntp_num)
{
e2k_size_t size = get_dump_analyze_bank_size(phys_bank, cntp_num);
e2k_size_t len = size;
e2k_addr_t base;
e2k_addr_t new_base;
BUG_ON(cntp_num == 0 || cntp_num == 1);
BUG_ON(cntp != cntp_num - 1);
base = phys_bank->base_addr;
new_base = LARGE_PAGE_ALIGN_DOWN(base);
len += phys_bank->pages_num * PAGE_SIZE -
((new_base - base) + size * cntp_num);
return len;
}
extern inline e2k_addr_t
get_dump_analyze_memory_offset(e2k_phys_bank_t *phys_bank, int cntp,
int cntp_num)
{
e2k_size_t size;
e2k_addr_t offset = 0;
e2k_addr_t base;
e2k_addr_t new_base;
BUG_ON(cntp_num == 0 || cntp_num == 1);
BUG_ON(cntp != cntp_num - 1);
size = get_dump_analyze_bank_size(phys_bank, cntp_num);
base = phys_bank->base_addr;
new_base = LARGE_PAGE_ALIGN_DOWN(base);
offset = (new_base - base) + size * cntp;
return offset;
}
extern inline e2k_addr_t
get_dump_analyze_memory_base(e2k_phys_bank_t *phys_bank, int cntp, int cntp_num)
{
e2k_addr_t offset = get_dump_analyze_memory_offset(
phys_bank, cntp, cntp_num);
e2k_addr_t base = phys_bank->base_addr;
base += offset;
return base;
}
extern inline e2k_addr_t
boot_get_dump_analyze_kernel_base(void)
{
e2k_phys_bank_t *phys_bank;
e2k_addr_t base;
e2k_addr_t new_base;
e2k_size_t cntp_size;
int node;
int bank;
for (node = 0; node < L_MAX_MEM_NUMNODES; node ++) {
phys_bank = full_phys_mem[node].banks;
if (phys_bank->pages_num == 0)
continue; /* node has not memory */
for (bank = 0; bank < L_MAX_NODE_PHYS_BANKS; bank ++) {
if (phys_bank->pages_num == 0)
break;
cntp_size = get_dump_analyze_memory_len(
phys_bank,
boot_cntp_small_kern_mem_div - 1,
boot_cntp_small_kern_mem_div);
if (cntp_size < boot_kernel_image_size)
goto next_bank;
base = get_dump_analyze_memory_base(
phys_bank,
boot_cntp_small_kern_mem_div - 1,
boot_cntp_small_kern_mem_div);
new_base = _PAGE_ALIGN_DOWN(base, E2K_KERNEL_PAGE_SIZE);
if (new_base - base + boot_kernel_image_size <=
cntp_size)
return new_base;
next_bank:
phys_bank ++;
}
}
/*
* TODO: avoid this
*/
BUG();
return -1;
}
/*
* bootblock manipulations (read/write/set/reset) in virtual kernel mode
* on physical level:
* write through and uncachable access on physical address
* bootblock virtual address can be only read
*/
static inline u64
read_bootblock_cur_cnt_point(bootblock_struct_t *bootblock)
{
return READ_BOOTBLOCK_FIELD(bootblock, cur_cnt_point);
}
extern inline void
write_bootblock_cur_cnt_point(bootblock_struct_t *bootblock, u64 new_cnt_point)
{
WRITE_BOOTBLOCK_FIELD(bootblock, cur_cnt_point, new_cnt_point);
}
extern inline void
write_bootblock_mem_cnt_points(bootblock_struct_t *bootblock, u64 new_mem_points)
{
WRITE_BOOTBLOCK_FIELD(bootblock, mem_cnt_points, new_mem_points);
}
extern inline void
write_bootblock_disk_cnt_points(bootblock_struct_t *bootblock,
u64 new_disk_points)
{
WRITE_BOOTBLOCK_FIELD(bootblock, disk_cnt_points, new_disk_points);
}
extern inline void
write_bootblock_kernel_base(bootblock_struct_t *bootblock,
u64 new_kernel_base)
{
WRITE_BOOTBLOCK_FIELD(bootblock, info.kernel_base, new_kernel_base);
}
extern inline u64
read_bootblock_cntp_kernel_base(bootblock_struct_t *bootblock, int cntp)
{
return READ_BOOTBLOCK_FIELD(bootblock,
info.cntp_info[cntp].kernel_base);
}
extern inline void
write_bootblock_cntp_kernel_base(bootblock_struct_t *bootblock, int cntp,
u64 kernel_base)
{
WRITE_BOOTBLOCK_FIELD(bootblock, info.cntp_info[cntp].kernel_base,
kernel_base);
}
extern inline void
set_bootblock_cntp_created(bootblock_struct_t *bootblock)
{
WRITE_BOOTBLOCK_FIELD(bootblock, cnt_points_created, 1);
}
/*
* Convert virtual address of kernel item in a control point context
* to the consistent physical address.
*/
#define cntp_va_to_pa(virt_addr, cntp_kernel_phys_base, ts) \
({ \
e2k_addr_t phys = 0; \
e2k_addr_t virt = (e2k_addr_t)virt_addr; \
\
if (virt > 0 && virt < PAGE_OFFSET) \
phys = cntp_user_address_to_phys(ts, virt); \
else if (virt >= PAGE_OFFSET && virt < PAGE_OFFSET + MAX_PM_SIZE) \
phys = __pa(virt); \
else if (virt >= KERNEL_BASE && virt <= KERNEL_END) \
phys = virt - KERNEL_BASE + cntp_kernel_phys_base; \
else if (virt != 0) \
phys = cntp_kernel_address_to_phys(virt); \
\
phys; \
})
#define cntp_va(virt_addr, ts) \
({ \
void *virt = (void*)0; \
if ((e2k_addr_t)virt_addr != 0) { \
virt = (void *) cntp_va_to_pa(virt_addr, cntp_kernel_base, ts);\
if (((unsigned long) virt) != -1) \
virt = __va(virt); \
} \
virt; \
})
#endif /* _E2K_CNT_POINT_H */