mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zdump: Extract dfi_mem_chunk module
To make dfi_mem_chunk API unit testable. Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
969a439aaa
commit
2df532c1fa
@@ -42,7 +42,7 @@ check_dep_zlib:
|
||||
all: check_dep_fuse check_dep_zlib zgetdump
|
||||
|
||||
OBJECTS = zgetdump.o opts.o zg.o \
|
||||
dfi.o dfi_vmcoreinfo.o \
|
||||
dfi.o dfi_mem_chunk.o dfi_vmcoreinfo.o \
|
||||
dfi_lkcd.o dfi_elf.o \
|
||||
dfi_s390.o dfi_s390_ext.o\
|
||||
dfi_s390mv.o dfi_s390mv_ext.o \
|
||||
|
||||
505
zdump/dfi.c
505
zdump/dfi.c
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "lib/util_log.h"
|
||||
#include "zgetdump.h"
|
||||
#include "dfi_mem_chunk.h"
|
||||
|
||||
#define TIME_FMT_STR "%a, %d %b %Y %H:%M:%S %z"
|
||||
#define PROGRESS_HASH_CNT 50
|
||||
@@ -49,17 +50,6 @@ struct cpus {
|
||||
unsigned int cnt;
|
||||
};
|
||||
|
||||
/*
|
||||
* Memory information
|
||||
*/
|
||||
struct mem {
|
||||
struct dfi_mem_chunk *chunk_cache;
|
||||
u64 start_addr;
|
||||
u64 end_addr;
|
||||
unsigned int chunk_cnt;
|
||||
struct util_list chunk_list;
|
||||
};
|
||||
|
||||
/*
|
||||
* Dump header attribute information
|
||||
*/
|
||||
@@ -83,8 +73,6 @@ struct attr {
|
||||
static struct {
|
||||
enum dfi_arch arch;
|
||||
struct attr attr;
|
||||
struct mem mem_phys;
|
||||
struct mem mem_virt;
|
||||
struct cpus cpus;
|
||||
struct dfi *dfi;
|
||||
unsigned long kdump_base;
|
||||
@@ -111,129 +99,6 @@ static void date_print(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize DFI memory chunks
|
||||
*/
|
||||
static void mem_init(struct mem *mem)
|
||||
{
|
||||
mem->start_addr = U64_MAX;
|
||||
mem->end_addr = 0;
|
||||
util_list_init(&mem->chunk_list, struct dfi_mem_chunk, list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory chunk compare function for list sorting
|
||||
*/
|
||||
static int mem_chunk_cmp_fn(void *a, void *b, void *UNUSED(data))
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk1 = a;
|
||||
struct dfi_mem_chunk *mem_chunk2 = b;
|
||||
|
||||
return mem_chunk1->start < mem_chunk2->start ? -1 : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update DFI memory chunks
|
||||
*/
|
||||
static void mem_update(struct mem *mem)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
|
||||
util_list_sort(&mem->chunk_list, mem_chunk_cmp_fn, NULL);
|
||||
mem->start_addr = U64_MAX;
|
||||
mem->end_addr = 0;
|
||||
util_list_iterate(&mem->chunk_list, mem_chunk) {
|
||||
mem->start_addr = MIN(mem->start_addr, mem_chunk->start);
|
||||
mem->end_addr = MAX(mem->end_addr, mem_chunk->end);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print memory map
|
||||
*/
|
||||
static void mem_map_print(void)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
u64 print_start = 0, print_end = 0;
|
||||
const char *zero_str;
|
||||
u32 volnr = 0;
|
||||
|
||||
STDERR("\nMemory map:\n");
|
||||
/*
|
||||
* Print each memory chunk if verbose specified
|
||||
*/
|
||||
if (g.opts.verbose) {
|
||||
dfi_mem_chunk_iterate(mem_chunk) {
|
||||
zero_str = "";
|
||||
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
|
||||
zero_str = " zeroes";
|
||||
STDERR(" %016llx - %016llx (%llu MB%s)\n",
|
||||
mem_chunk->start, mem_chunk->end,
|
||||
TO_MIB(mem_chunk->size), zero_str);
|
||||
}
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Merge adjacent memory chunks from the same volume
|
||||
*/
|
||||
dfi_mem_chunk_iterate(mem_chunk) {
|
||||
if (print_end == 0) {
|
||||
print_start = mem_chunk->start;
|
||||
print_end = mem_chunk->end;
|
||||
volnr = mem_chunk->volnr;
|
||||
continue;
|
||||
}
|
||||
if (mem_chunk->start != print_end + 1 ||
|
||||
mem_chunk->volnr != volnr) {
|
||||
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
|
||||
print_end, TO_MIB(print_end - print_start + 1));
|
||||
print_start = mem_chunk->start;
|
||||
volnr = mem_chunk->volnr;
|
||||
}
|
||||
print_end = mem_chunk->end;
|
||||
}
|
||||
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
|
||||
print_end, TO_MIB(print_end - print_start + 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Is memory range valid?
|
||||
*/
|
||||
int dfi_mem_range_valid(u64 addr, u64 len)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
u64 addr_end = addr + len;
|
||||
|
||||
/* check for unsigned wrap */
|
||||
if (addr_end < addr)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
mem_chunk = dfi_mem_chunk_find(addr);
|
||||
if (!mem_chunk)
|
||||
return 0;
|
||||
addr += MIN(len, mem_chunk->end - addr + 1);
|
||||
} while (addr < addr_end);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is memory already mapped at range?
|
||||
*/
|
||||
static int mem_range_mapped(u64 start, u64 size)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
u64 end = start + size - 1;
|
||||
|
||||
dfi_mem_chunk_iterate(mem_chunk) {
|
||||
if (mem_chunk->start > end)
|
||||
continue;
|
||||
if (mem_chunk->end < start)
|
||||
continue;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Print dump information (--info option)
|
||||
*/
|
||||
@@ -273,250 +138,13 @@ void dfi_info_print(void)
|
||||
STDERR(" Dump file size.....: %lld MB\n",
|
||||
TO_MIB(*l.attr.file_size));
|
||||
if (dfi_mem_range())
|
||||
mem_map_print();
|
||||
dfi_mem_map_print(g.opts.verbose);
|
||||
if (l.dfi->info_dump) {
|
||||
STDERR("\nDump device info:\n");
|
||||
l.dfi->info_dump();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add memory chunk to memory
|
||||
*/
|
||||
static void mem_chunk_create(struct mem *mem, u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
|
||||
mem_chunk = zg_alloc(sizeof(*mem_chunk));
|
||||
mem_chunk->start = start;
|
||||
mem_chunk->end = start + size - 1;
|
||||
mem_chunk->size = size;
|
||||
mem_chunk->read_fn = read_fn;
|
||||
mem_chunk->free_fn = free_fn;
|
||||
mem_chunk->data = data;
|
||||
|
||||
util_list_add_tail(&mem->chunk_list, mem_chunk);
|
||||
mem->start_addr = MIN(mem->start_addr, mem_chunk->start);
|
||||
mem->end_addr = MAX(mem->end_addr, mem_chunk->end);
|
||||
mem->chunk_cache = mem_chunk;
|
||||
mem->chunk_cnt++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if memory chunk contains address
|
||||
*/
|
||||
static int mem_chunk_has_addr(struct dfi_mem_chunk *mem_chunk, u64 addr)
|
||||
{
|
||||
return (addr >= mem_chunk->start && addr <= mem_chunk->end);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find memory chunk that contains address
|
||||
*/
|
||||
static struct dfi_mem_chunk *mem_chunk_find(struct mem *mem, u64 addr)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
|
||||
if (mem->chunk_cache && mem_chunk_has_addr(mem->chunk_cache, addr))
|
||||
return mem->chunk_cache;
|
||||
util_list_iterate(&mem->chunk_list, mem_chunk) {
|
||||
if (mem_chunk_has_addr(mem_chunk, addr)) {
|
||||
mem->chunk_cache = mem_chunk;
|
||||
return mem_chunk;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read memory at given address
|
||||
*/
|
||||
static void mem_read(struct mem *mem, u64 addr, void *buf, size_t cnt)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
u64 size, off, copied = 0;
|
||||
|
||||
while (copied != cnt) {
|
||||
mem_chunk = mem_chunk_find(mem, addr);
|
||||
size = MIN(cnt - copied, mem_chunk->end - addr + 1);
|
||||
off = addr - mem_chunk->start;
|
||||
mem_chunk->read_fn(mem_chunk, off, buf + copied, size);
|
||||
copied += size;
|
||||
addr += size;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read memory for virtual map memory chunk
|
||||
*/
|
||||
static void mem_chunk_map_read_fn(struct dfi_mem_chunk *mem_chunk, u64 off,
|
||||
void *buf, u64 cnt)
|
||||
{
|
||||
u64 *start = mem_chunk->data;
|
||||
|
||||
dfi_mem_phys_read(*start + off, buf, cnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if memory chunk is a virtual mapping
|
||||
*/
|
||||
static int mem_chunk_is_map(struct dfi_mem_chunk *mem_chunk)
|
||||
{
|
||||
return mem_chunk->read_fn == mem_chunk_map_read_fn;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return physical start address for memory chunk
|
||||
*/
|
||||
static u64 mem_chunk_start_phys(struct dfi_mem_chunk *mem_chunk)
|
||||
{
|
||||
if (mem_chunk_is_map(mem_chunk))
|
||||
return *((u64 *) mem_chunk->data);
|
||||
else
|
||||
return mem_chunk->start;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add virtual memory chunk with simple virtual mapping
|
||||
*/
|
||||
static void mem_chunk_map_add(u64 start, u64 size, u64 start_p)
|
||||
{
|
||||
u64 *data = zg_alloc(sizeof(*data));
|
||||
|
||||
*data = start_p;
|
||||
dfi_mem_chunk_virt_add(start, size, data, mem_chunk_map_read_fn,
|
||||
zg_free);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add virtual memory chunk
|
||||
*/
|
||||
void dfi_mem_chunk_virt_add(u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn)
|
||||
{
|
||||
util_log_print(UTIL_LOG_DEBUG,
|
||||
"DFI add %svirt mem chunk start 0x%016lx size 0x%016lx\n",
|
||||
read_fn == dfi_mem_chunk_read_zero ? "zero " : "",
|
||||
start, size);
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, free_fn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add memory chunk with volume index
|
||||
*/
|
||||
void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn,
|
||||
u32 volnr)
|
||||
{
|
||||
util_log_print(UTIL_LOG_DEBUG,
|
||||
"DFI add %svol mem chunk start 0x%016lx size 0x%016lx volnr %u\n",
|
||||
read_fn == dfi_mem_chunk_read_zero ? "zero " : "",
|
||||
start, size, volnr);
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
mem_chunk_create(&l.mem_phys, start, size, data, read_fn, free_fn);
|
||||
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, NULL);
|
||||
l.mem_virt.chunk_cache->volnr = volnr;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Add memory chunk
|
||||
*/
|
||||
void dfi_mem_chunk_add(u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn)
|
||||
{
|
||||
dfi_mem_chunk_add_vol(start, size, data, read_fn, free_fn, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read zero pages
|
||||
*/
|
||||
void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
|
||||
u64 UNUSED(off), void *buf, u64 cnt)
|
||||
{
|
||||
memset(buf, 0, cnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return mem_chunk list head
|
||||
*/
|
||||
struct util_list *dfi_mem_chunk_list(void)
|
||||
{
|
||||
return &l.mem_virt.chunk_list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return number of memory chunks in input dump
|
||||
*/
|
||||
unsigned int dfi_mem_chunk_cnt(void)
|
||||
{
|
||||
return l.mem_virt.chunk_cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return maximum memory range
|
||||
*/
|
||||
u64 dfi_mem_range(void)
|
||||
{
|
||||
if (l.mem_virt.start_addr == U64_MAX)
|
||||
return 0;
|
||||
return l.mem_virt.end_addr - l.mem_virt.start_addr + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return first memory chunk
|
||||
*/
|
||||
struct dfi_mem_chunk *dfi_mem_chunk_first(void)
|
||||
{
|
||||
if (util_list_is_empty(&l.mem_virt.chunk_list))
|
||||
return NULL;
|
||||
return util_list_start(&l.mem_virt.chunk_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return last memory chunk
|
||||
*/
|
||||
struct dfi_mem_chunk *dfi_mem_chunk_last(void)
|
||||
{
|
||||
if (util_list_is_empty(&l.mem_virt.chunk_list))
|
||||
return NULL;
|
||||
return util_list_end(&l.mem_virt.chunk_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return next memory chunk
|
||||
*/
|
||||
struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *mem_chunk)
|
||||
{
|
||||
return util_list_next(&l.mem_virt.chunk_list, mem_chunk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return previous memory chunk
|
||||
*/
|
||||
struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *mem_chunk)
|
||||
{
|
||||
return util_list_prev(&l.mem_virt.chunk_list, mem_chunk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find memory chunk for given address
|
||||
*/
|
||||
struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr)
|
||||
{
|
||||
return mem_chunk_find(&l.mem_virt, addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize CPU info
|
||||
*/
|
||||
@@ -616,39 +244,6 @@ struct util_list *dfi_cpu_list(void)
|
||||
return &l.cpus.list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read memory at given address and do kdump swap if necessary
|
||||
*/
|
||||
void dfi_mem_read(u64 addr, void *buf, size_t cnt)
|
||||
{
|
||||
util_log_print(UTIL_LOG_TRACE,
|
||||
"DFI virt mem read addr 0x%016lx size 0x%016lx\n",
|
||||
addr, cnt);
|
||||
mem_read(&l.mem_virt, addr, buf, cnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read physical memory at given address
|
||||
*/
|
||||
void dfi_mem_phys_read(u64 addr, void *buf, size_t cnt)
|
||||
{
|
||||
util_log_print(UTIL_LOG_TRACE,
|
||||
"DFI phys mem read addr 0x%016lx size 0x%016lx\n",
|
||||
addr, cnt);
|
||||
mem_read(&l.mem_phys, addr, buf, cnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read memory at given address with return code
|
||||
*/
|
||||
int dfi_mem_read_rc(u64 addr, void *buf, size_t cnt)
|
||||
{
|
||||
if (!dfi_mem_range_valid(addr, cnt))
|
||||
return -EINVAL;
|
||||
dfi_mem_read(addr, buf, cnt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get input dump format name
|
||||
*/
|
||||
@@ -1009,89 +604,6 @@ unsigned long dfi_kdump_base(void)
|
||||
return l.kdump_base;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmap memory region
|
||||
*/
|
||||
static void mem_unmap(u64 start, u64 size)
|
||||
{
|
||||
u64 start_phys, end_phys, addr_phys, addr_virt, size_virt;
|
||||
struct dfi_mem_chunk *mem_chunk, *tmp;
|
||||
u64 end = start + size - 1;
|
||||
|
||||
util_list_iterate_safe(&l.mem_virt.chunk_list, mem_chunk, tmp) {
|
||||
/*
|
||||
* Chunk not hit?
|
||||
*/
|
||||
if (mem_chunk->start >= start + size)
|
||||
continue;
|
||||
if (mem_chunk->end < start)
|
||||
continue;
|
||||
/*
|
||||
* Chunk completely unmapped
|
||||
*
|
||||
* UNMAP: UUUUUUUUU || UUUUUU
|
||||
* CHUNK: CCCC || CCCCCC
|
||||
* TO:
|
||||
*/
|
||||
if (mem_chunk->start >= start && mem_chunk->end <= end)
|
||||
goto free;
|
||||
|
||||
/*
|
||||
* Get real start and end addresses
|
||||
*/
|
||||
start_phys = mem_chunk_start_phys(mem_chunk);
|
||||
end_phys = start_phys + mem_chunk->size - 1;
|
||||
|
||||
/*
|
||||
* Chunk hit at start or in the middle?
|
||||
*
|
||||
* UNMAP: UUUUUU || UU || UUU
|
||||
* CHUNK: CCCCC || CCCCCC || CCCC
|
||||
* TO: NN || NN || NNN
|
||||
*/
|
||||
if (mem_chunk->end > end) {
|
||||
addr_virt = end + 1;
|
||||
size_virt = mem_chunk->end - end;
|
||||
addr_phys = end_phys - size_virt + 1;
|
||||
mem_chunk_map_add(addr_virt, size_virt, addr_phys);
|
||||
}
|
||||
/*
|
||||
* Chunk hit at end or in the middle?
|
||||
*
|
||||
* UNMAP: UUUUUU || UU || UUU
|
||||
* CHUNK: CCCCC || CCCCCC || CCC
|
||||
* TO: NN || NN || NN
|
||||
*/
|
||||
if (mem_chunk->start < start) {
|
||||
addr_virt = mem_chunk->start;
|
||||
size_virt = start - addr_virt;
|
||||
addr_phys = start_phys;
|
||||
mem_chunk_map_add(addr_virt, size_virt, addr_phys);
|
||||
}
|
||||
free:
|
||||
util_list_remove(&l.mem_virt.chunk_list, mem_chunk);
|
||||
l.mem_virt.chunk_cnt--;
|
||||
if (mem_chunk->data && mem_chunk->free_fn)
|
||||
mem_chunk->free_fn(mem_chunk->data);
|
||||
zg_free(mem_chunk);
|
||||
}
|
||||
mem_update(&l.mem_virt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Map memory region
|
||||
*/
|
||||
static void mem_map(u64 start, u64 size, u64 start_phys)
|
||||
{
|
||||
if (mem_range_mapped(start, size)) {
|
||||
mem_map_print();
|
||||
ABORT("Map request for already mapped region (%llx/%llx/%llx)",
|
||||
start, size, start_phys);
|
||||
}
|
||||
mem_chunk_map_add(start, size, start_phys);
|
||||
mem_update(&l.mem_virt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if dump contains a kdump dump and initialize kdump_base and kdump_size
|
||||
*/
|
||||
@@ -1127,11 +639,11 @@ static void kdump_init(void)
|
||||
if (!g.opts.select_specified)
|
||||
return;
|
||||
if (g.opts.select == OPTS_SELECT_PROD) {
|
||||
mem_unmap(0, size);
|
||||
mem_unmap(base, size);
|
||||
mem_map(0, size, base);
|
||||
dfi_mem_unmap(0, size);
|
||||
dfi_mem_unmap(base, size);
|
||||
dfi_mem_map(0, size, base);
|
||||
} else if (g.opts.select == OPTS_SELECT_KDUMP) {
|
||||
mem_unmap(l.kdump_size, U64_MAX - l.kdump_size);
|
||||
dfi_mem_unmap(l.kdump_size, U64_MAX - l.kdump_size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1244,8 +756,9 @@ int dfi_init(void)
|
||||
util_log_print(UTIL_LOG_TRACE, "DFI initialization\n");
|
||||
|
||||
l.arch = DFI_ARCH_UNKNOWN;
|
||||
mem_init(&l.mem_virt);
|
||||
mem_init(&l.mem_phys);
|
||||
rc = dfi_mem_chunk_init();
|
||||
if (rc)
|
||||
return rc;
|
||||
attr_init();
|
||||
dfi_cpu_info_init(DFI_CPU_CONTENT_NONE);
|
||||
while ((dfi = dfi_vec[i])) {
|
||||
|
||||
53
zdump/dfi.h
53
zdump/dfi.h
@@ -17,7 +17,7 @@
|
||||
#include "lib/zt_common.h"
|
||||
#include "lib/util_list.h"
|
||||
|
||||
#include "zg.h"
|
||||
#include "dfi_mem_chunk.h"
|
||||
|
||||
/*
|
||||
* CPU info functions and definitions
|
||||
@@ -148,51 +148,6 @@ extern int dfi_cpu_add_from_lc(u32 lc_addr);
|
||||
extern int dfi_cpu_lc_has_vx_sa(void *lc);
|
||||
extern void dfi_cpu_vx_copy(void *buf, struct dfi_cpu *cpu);
|
||||
|
||||
/*
|
||||
* Mem chunk functions and definitions
|
||||
*/
|
||||
struct dfi_mem_chunk;
|
||||
|
||||
typedef void (*dfi_mem_chunk_read_fn)(struct dfi_mem_chunk *mem_chunk,
|
||||
u64 off, void *buf, u64 cnt);
|
||||
typedef void (*dfi_mem_chunk_free_fn)(void *data);
|
||||
|
||||
struct dfi_mem_chunk {
|
||||
struct util_list_node list; /* List */
|
||||
u64 start; /* Start address in memory */
|
||||
u64 end; /* End address in memory */
|
||||
u64 size; /* Size of chunk in dump file */
|
||||
dfi_mem_chunk_read_fn read_fn; /* Chunk read callback */
|
||||
dfi_mem_chunk_free_fn free_fn; /* Free data callback */
|
||||
void *data; /* Data for callback */
|
||||
u32 volnr; /* Volume id where chunk resides */
|
||||
};
|
||||
|
||||
extern void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
|
||||
u64 UNUSED(off), void *buf, u64 cnt);
|
||||
extern void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn,
|
||||
u32 volnr);
|
||||
extern void dfi_mem_chunk_add(u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn);
|
||||
extern void dfi_mem_chunk_virt_add(u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn);
|
||||
extern u64 dfi_mem_range(void);
|
||||
extern int dfi_mem_range_valid(u64 addr, u64 len);
|
||||
extern unsigned int dfi_mem_chunk_cnt(void);
|
||||
extern struct dfi_mem_chunk *dfi_mem_chunk_first(void);
|
||||
extern struct dfi_mem_chunk *dfi_mem_chunk_last(void);
|
||||
extern struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *chunk);
|
||||
extern struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *chunk);
|
||||
extern struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr);
|
||||
|
||||
extern struct util_list *dfi_mem_chunk_list(void);
|
||||
#define dfi_mem_chunk_iterate(mem_chunk) \
|
||||
util_list_iterate(dfi_mem_chunk_list(), mem_chunk)
|
||||
|
||||
/*
|
||||
* Dump header attribute set/get functions
|
||||
*/
|
||||
@@ -229,12 +184,6 @@ extern enum dfi_arch *dfi_attr_build_arch(void);
|
||||
extern void dfi_attr_real_cpu_cnt_set(u32 real_cpu_cnt);
|
||||
extern u32 *dfi_attr_real_cpu_cnt(void);
|
||||
|
||||
/*
|
||||
* DFI external functions
|
||||
*/
|
||||
extern void dfi_mem_read(u64 addr, void *buf, size_t cnt);
|
||||
extern int dfi_mem_read_rc(u64 addr, void *buf, size_t cnt);
|
||||
extern void dfi_mem_phys_read(u64 addr, void *buf, size_t cnt);
|
||||
extern void dfi_info_print(void);
|
||||
|
||||
/*
|
||||
|
||||
524
zdump/dfi_mem_chunk.c
Normal file
524
zdump/dfi_mem_chunk.c
Normal file
@@ -0,0 +1,524 @@
|
||||
/*
|
||||
* Copyright IBM Corp. 2001, 2018
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/util_log.h"
|
||||
|
||||
#include "zg.h"
|
||||
#include "dfi_mem_chunk.h"
|
||||
|
||||
/*
|
||||
* Memory information
|
||||
*/
|
||||
struct mem {
|
||||
struct dfi_mem_chunk *chunk_cache;
|
||||
u64 start_addr;
|
||||
u64 end_addr;
|
||||
unsigned int chunk_cnt;
|
||||
struct util_list chunk_list;
|
||||
};
|
||||
|
||||
/*
|
||||
* File local static data
|
||||
*/
|
||||
static struct {
|
||||
struct mem mem_phys;
|
||||
struct mem mem_virt;
|
||||
} l;
|
||||
|
||||
/*
|
||||
* Initialize DFI memory chunks
|
||||
*/
|
||||
static void mem_init(struct mem *mem)
|
||||
{
|
||||
mem->start_addr = U64_MAX;
|
||||
mem->end_addr = 0;
|
||||
util_list_init(&mem->chunk_list, struct dfi_mem_chunk, list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Memory chunk compare function for list sorting
|
||||
*/
|
||||
static int mem_chunk_cmp_fn(void *a, void *b, void *UNUSED(data))
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk1 = a;
|
||||
struct dfi_mem_chunk *mem_chunk2 = b;
|
||||
|
||||
return mem_chunk1->start < mem_chunk2->start ? -1 : 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Update DFI memory chunks
|
||||
*/
|
||||
static void mem_update(struct mem *mem)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
|
||||
util_list_sort(&mem->chunk_list, mem_chunk_cmp_fn, NULL);
|
||||
mem->start_addr = U64_MAX;
|
||||
mem->end_addr = 0;
|
||||
util_list_iterate(&mem->chunk_list, mem_chunk) {
|
||||
mem->start_addr = MIN(mem->start_addr, mem_chunk->start);
|
||||
mem->end_addr = MAX(mem->end_addr, mem_chunk->end);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print memory map
|
||||
*/
|
||||
void dfi_mem_map_print(bool verbose)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
u64 print_start = 0, print_end = 0;
|
||||
const char *zero_str;
|
||||
u32 volnr = 0;
|
||||
|
||||
STDERR("\nMemory map:\n");
|
||||
/*
|
||||
* Print each memory chunk if verbose specified
|
||||
*/
|
||||
if (verbose) {
|
||||
dfi_mem_chunk_iterate(mem_chunk) {
|
||||
zero_str = "";
|
||||
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
|
||||
zero_str = " zeroes";
|
||||
STDERR(" %016llx - %016llx (%llu MB%s)\n",
|
||||
mem_chunk->start, mem_chunk->end,
|
||||
TO_MIB(mem_chunk->size), zero_str);
|
||||
}
|
||||
return;
|
||||
}
|
||||
/*
|
||||
* Merge adjacent memory chunks from the same volume
|
||||
*/
|
||||
dfi_mem_chunk_iterate(mem_chunk) {
|
||||
if (print_end == 0) {
|
||||
print_start = mem_chunk->start;
|
||||
print_end = mem_chunk->end;
|
||||
volnr = mem_chunk->volnr;
|
||||
continue;
|
||||
}
|
||||
if (mem_chunk->start != print_end + 1 ||
|
||||
mem_chunk->volnr != volnr) {
|
||||
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
|
||||
print_end, TO_MIB(print_end - print_start + 1));
|
||||
print_start = mem_chunk->start;
|
||||
volnr = mem_chunk->volnr;
|
||||
}
|
||||
print_end = mem_chunk->end;
|
||||
}
|
||||
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
|
||||
print_end, TO_MIB(print_end - print_start + 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Is memory range valid?
|
||||
*/
|
||||
int dfi_mem_range_valid(u64 addr, u64 len)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
u64 addr_end = addr + len;
|
||||
|
||||
/* check for unsigned wrap */
|
||||
if (addr_end < addr)
|
||||
return 0;
|
||||
|
||||
do {
|
||||
mem_chunk = dfi_mem_chunk_find(addr);
|
||||
if (!mem_chunk)
|
||||
return 0;
|
||||
addr += MIN(len, mem_chunk->end - addr + 1);
|
||||
} while (addr < addr_end);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Is memory already mapped at range?
|
||||
*/
|
||||
static int mem_range_mapped(u64 start, u64 size)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
u64 end = start + size - 1;
|
||||
|
||||
dfi_mem_chunk_iterate(mem_chunk) {
|
||||
if (mem_chunk->start > end)
|
||||
continue;
|
||||
if (mem_chunk->end < start)
|
||||
continue;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add memory chunk to memory
|
||||
*/
|
||||
static void mem_chunk_create(struct mem *mem, u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
|
||||
mem_chunk = util_malloc(sizeof(*mem_chunk));
|
||||
mem_chunk->start = start;
|
||||
mem_chunk->end = start + size - 1;
|
||||
mem_chunk->size = size;
|
||||
mem_chunk->read_fn = read_fn;
|
||||
mem_chunk->free_fn = free_fn;
|
||||
mem_chunk->data = data;
|
||||
|
||||
util_list_add_tail(&mem->chunk_list, mem_chunk);
|
||||
mem->start_addr = MIN(mem->start_addr, mem_chunk->start);
|
||||
mem->end_addr = MAX(mem->end_addr, mem_chunk->end);
|
||||
mem->chunk_cache = mem_chunk;
|
||||
mem->chunk_cnt++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if memory chunk contains address
|
||||
*/
|
||||
static int mem_chunk_has_addr(struct dfi_mem_chunk *mem_chunk, u64 addr)
|
||||
{
|
||||
return (addr >= mem_chunk->start && addr <= mem_chunk->end);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find memory chunk that contains address
|
||||
*/
|
||||
static struct dfi_mem_chunk *mem_chunk_find(struct mem *mem, u64 addr)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
|
||||
if (mem->chunk_cache && mem_chunk_has_addr(mem->chunk_cache, addr))
|
||||
return mem->chunk_cache;
|
||||
util_list_iterate(&mem->chunk_list, mem_chunk) {
|
||||
if (mem_chunk_has_addr(mem_chunk, addr)) {
|
||||
mem->chunk_cache = mem_chunk;
|
||||
return mem_chunk;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read memory at given address
|
||||
*/
|
||||
static void mem_read(struct mem *mem, u64 addr, void *buf, size_t cnt)
|
||||
{
|
||||
struct dfi_mem_chunk *mem_chunk;
|
||||
u64 size, off, copied = 0;
|
||||
|
||||
while (copied != cnt) {
|
||||
mem_chunk = mem_chunk_find(mem, addr);
|
||||
size = MIN(cnt - copied, mem_chunk->end - addr + 1);
|
||||
off = addr - mem_chunk->start;
|
||||
mem_chunk->read_fn(mem_chunk, off, buf + copied, size);
|
||||
copied += size;
|
||||
addr += size;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read memory for virtual map memory chunk
|
||||
*/
|
||||
static void mem_chunk_map_read_fn(struct dfi_mem_chunk *mem_chunk, u64 off,
|
||||
void *buf, u64 cnt)
|
||||
{
|
||||
u64 *start = mem_chunk->data;
|
||||
|
||||
dfi_mem_phys_read(*start + off, buf, cnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if memory chunk is a virtual mapping
|
||||
*/
|
||||
static int mem_chunk_is_map(struct dfi_mem_chunk *mem_chunk)
|
||||
{
|
||||
return mem_chunk->read_fn == mem_chunk_map_read_fn;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return physical start address for memory chunk
|
||||
*/
|
||||
static u64 mem_chunk_start_phys(struct dfi_mem_chunk *mem_chunk)
|
||||
{
|
||||
if (mem_chunk_is_map(mem_chunk))
|
||||
return *((u64 *) mem_chunk->data);
|
||||
else
|
||||
return mem_chunk->start;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add virtual memory chunk with simple virtual mapping
|
||||
*/
|
||||
static void mem_chunk_map_add(u64 start, u64 size, u64 start_p)
|
||||
{
|
||||
u64 *data = util_malloc(sizeof(*data));
|
||||
|
||||
*data = start_p;
|
||||
dfi_mem_chunk_virt_add(start, size, data, mem_chunk_map_read_fn, free);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add virtual memory chunk
|
||||
*/
|
||||
void dfi_mem_chunk_virt_add(u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn)
|
||||
{
|
||||
util_log_print(UTIL_LOG_DEBUG,
|
||||
"DFI add %svirt mem chunk start 0x%016lx size 0x%016lx\n",
|
||||
read_fn == dfi_mem_chunk_read_zero ? "zero " : "",
|
||||
start, size);
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, free_fn);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add memory chunk with volume index
|
||||
*/
|
||||
void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn,
|
||||
u32 volnr)
|
||||
{
|
||||
util_log_print(UTIL_LOG_DEBUG,
|
||||
"DFI add %svol mem chunk start 0x%016lx size 0x%016lx volnr %u\n",
|
||||
read_fn == dfi_mem_chunk_read_zero ? "zero " : "",
|
||||
start, size, volnr);
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
mem_chunk_create(&l.mem_phys, start, size, data, read_fn, free_fn);
|
||||
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, NULL);
|
||||
l.mem_virt.chunk_cache->volnr = volnr;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Add memory chunk
|
||||
*/
|
||||
void dfi_mem_chunk_add(u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn)
|
||||
{
|
||||
dfi_mem_chunk_add_vol(start, size, data, read_fn, free_fn, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read zero pages
|
||||
*/
|
||||
void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
|
||||
u64 UNUSED(off), void *buf, u64 cnt)
|
||||
{
|
||||
memset(buf, 0, cnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return mem_chunk list head
|
||||
*/
|
||||
struct util_list *dfi_mem_chunk_list(void)
|
||||
{
|
||||
return &l.mem_virt.chunk_list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return number of memory chunks in input dump
|
||||
*/
|
||||
unsigned int dfi_mem_chunk_cnt(void)
|
||||
{
|
||||
return l.mem_virt.chunk_cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return maximum memory range
|
||||
*/
|
||||
u64 dfi_mem_range(void)
|
||||
{
|
||||
if (l.mem_virt.start_addr == U64_MAX)
|
||||
return 0;
|
||||
return l.mem_virt.end_addr - l.mem_virt.start_addr + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return first memory chunk
|
||||
*/
|
||||
struct dfi_mem_chunk *dfi_mem_chunk_first(void)
|
||||
{
|
||||
if (util_list_is_empty(&l.mem_virt.chunk_list))
|
||||
return NULL;
|
||||
return util_list_start(&l.mem_virt.chunk_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return last memory chunk
|
||||
*/
|
||||
struct dfi_mem_chunk *dfi_mem_chunk_last(void)
|
||||
{
|
||||
if (util_list_is_empty(&l.mem_virt.chunk_list))
|
||||
return NULL;
|
||||
return util_list_end(&l.mem_virt.chunk_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return next memory chunk
|
||||
*/
|
||||
struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *mem_chunk)
|
||||
{
|
||||
return util_list_next(&l.mem_virt.chunk_list, mem_chunk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return previous memory chunk
|
||||
*/
|
||||
struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *mem_chunk)
|
||||
{
|
||||
return util_list_prev(&l.mem_virt.chunk_list, mem_chunk);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find memory chunk for given address
|
||||
*/
|
||||
struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr)
|
||||
{
|
||||
return mem_chunk_find(&l.mem_virt, addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read memory at given address and do kdump swap if necessary
|
||||
*/
|
||||
void dfi_mem_read(u64 addr, void *buf, size_t cnt)
|
||||
{
|
||||
util_log_print(UTIL_LOG_TRACE,
|
||||
"DFI virt mem read addr 0x%016lx size 0x%016lx\n",
|
||||
addr, cnt);
|
||||
mem_read(&l.mem_virt, addr, buf, cnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read physical memory at given address
|
||||
*/
|
||||
void dfi_mem_phys_read(u64 addr, void *buf, size_t cnt)
|
||||
{
|
||||
util_log_print(UTIL_LOG_TRACE,
|
||||
"DFI phys mem read addr 0x%016lx size 0x%016lx\n",
|
||||
addr, cnt);
|
||||
mem_read(&l.mem_phys, addr, buf, cnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read memory at given address with return code
|
||||
*/
|
||||
int dfi_mem_read_rc(u64 addr, void *buf, size_t cnt)
|
||||
{
|
||||
if (!dfi_mem_range_valid(addr, cnt))
|
||||
return -EINVAL;
|
||||
dfi_mem_read(addr, buf, cnt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unmap memory region
|
||||
*/
|
||||
void dfi_mem_unmap(u64 start, u64 size)
|
||||
{
|
||||
u64 start_phys, end_phys, addr_phys, addr_virt, size_virt;
|
||||
struct dfi_mem_chunk *mem_chunk, *tmp;
|
||||
u64 end = start + size - 1;
|
||||
|
||||
util_list_iterate_safe(&l.mem_virt.chunk_list, mem_chunk, tmp) {
|
||||
/*
|
||||
* Chunk not hit?
|
||||
*/
|
||||
if (mem_chunk->start >= start + size)
|
||||
continue;
|
||||
if (mem_chunk->end < start)
|
||||
continue;
|
||||
/*
|
||||
* Chunk completely unmapped
|
||||
*
|
||||
* UNMAP: UUUUUUUUU || UUUUUU
|
||||
* CHUNK: CCCC || CCCCCC
|
||||
* TO:
|
||||
*/
|
||||
if (mem_chunk->start >= start && mem_chunk->end <= end)
|
||||
goto free;
|
||||
|
||||
/*
|
||||
* Get real start and end addresses
|
||||
*/
|
||||
start_phys = mem_chunk_start_phys(mem_chunk);
|
||||
end_phys = start_phys + mem_chunk->size - 1;
|
||||
|
||||
/*
|
||||
* Chunk hit at start or in the middle?
|
||||
*
|
||||
* UNMAP: UUUUUU || UU || UUU
|
||||
* CHUNK: CCCCC || CCCCCC || CCCC
|
||||
* TO: NN || NN || NNN
|
||||
*/
|
||||
if (mem_chunk->end > end) {
|
||||
addr_virt = end + 1;
|
||||
size_virt = mem_chunk->end - end;
|
||||
addr_phys = end_phys - size_virt + 1;
|
||||
mem_chunk_map_add(addr_virt, size_virt, addr_phys);
|
||||
}
|
||||
/*
|
||||
* Chunk hit at end or in the middle?
|
||||
*
|
||||
* UNMAP: UUUUUU || UU || UUU
|
||||
* CHUNK: CCCCC || CCCCCC || CCC
|
||||
* TO: NN || NN || NN
|
||||
*/
|
||||
if (mem_chunk->start < start) {
|
||||
addr_virt = mem_chunk->start;
|
||||
size_virt = start - addr_virt;
|
||||
addr_phys = start_phys;
|
||||
mem_chunk_map_add(addr_virt, size_virt, addr_phys);
|
||||
}
|
||||
free:
|
||||
util_list_remove(&l.mem_virt.chunk_list, mem_chunk);
|
||||
l.mem_virt.chunk_cnt--;
|
||||
if (mem_chunk->data && mem_chunk->free_fn)
|
||||
mem_chunk->free_fn(mem_chunk->data);
|
||||
free(mem_chunk);
|
||||
}
|
||||
mem_update(&l.mem_virt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Map memory region
|
||||
*/
|
||||
void dfi_mem_map(u64 start, u64 size, u64 start_phys)
|
||||
{
|
||||
if (mem_range_mapped(start, size)) {
|
||||
dfi_mem_map_print(false);
|
||||
ABORT("Map request for already mapped region (%llx/%llx/%llx)",
|
||||
start, size, start_phys);
|
||||
}
|
||||
mem_chunk_map_add(start, size, start_phys);
|
||||
mem_update(&l.mem_virt);
|
||||
}
|
||||
|
||||
int dfi_mem_chunk_init(void)
|
||||
{
|
||||
mem_init(&l.mem_virt);
|
||||
mem_init(&l.mem_phys);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dfi_mem_chunk_deinit(void)
|
||||
{
|
||||
memset(&l, 0, sizeof(l));
|
||||
}
|
||||
76
zdump/dfi_mem_chunk.h
Normal file
76
zdump/dfi_mem_chunk.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright IBM Corp. 2001, 2018
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef DFI_MEM_CHUNK_H
|
||||
#define DFI_MEM_CHUNK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
#include "lib/util_list.h"
|
||||
|
||||
/*
|
||||
* Mem chunk functions and definitions
|
||||
*/
|
||||
struct dfi_mem_chunk;
|
||||
|
||||
typedef void (*dfi_mem_chunk_read_fn)(struct dfi_mem_chunk *mem_chunk,
|
||||
u64 off, void *buf, u64 cnt);
|
||||
typedef void (*dfi_mem_chunk_free_fn)(void *data);
|
||||
|
||||
struct dfi_mem_chunk {
|
||||
struct util_list_node list; /* List */
|
||||
u64 start; /* Start address in memory */
|
||||
u64 end; /* End address in memory */
|
||||
u64 size; /* Size of chunk in dump file */
|
||||
dfi_mem_chunk_read_fn read_fn; /* Chunk read callback */
|
||||
dfi_mem_chunk_free_fn free_fn; /* Free data callback */
|
||||
void *data; /* Data for callback */
|
||||
u32 volnr; /* Volume id where chunk resides */
|
||||
};
|
||||
|
||||
extern void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
|
||||
u64 UNUSED(off), void *buf, u64 cnt);
|
||||
extern void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn,
|
||||
u32 volnr);
|
||||
extern void dfi_mem_chunk_add(u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn);
|
||||
extern void dfi_mem_chunk_virt_add(u64 start, u64 size, void *data,
|
||||
dfi_mem_chunk_read_fn read_fn,
|
||||
dfi_mem_chunk_free_fn free_fn);
|
||||
extern u64 dfi_mem_range(void);
|
||||
extern int dfi_mem_range_valid(u64 addr, u64 len);
|
||||
extern unsigned int dfi_mem_chunk_cnt(void);
|
||||
extern struct dfi_mem_chunk *dfi_mem_chunk_first(void);
|
||||
extern struct dfi_mem_chunk *dfi_mem_chunk_last(void);
|
||||
extern struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *chunk);
|
||||
extern struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *chunk);
|
||||
extern struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr);
|
||||
|
||||
extern struct util_list *dfi_mem_chunk_list(void);
|
||||
#define dfi_mem_chunk_iterate(mem_chunk) \
|
||||
util_list_iterate(dfi_mem_chunk_list(), mem_chunk)
|
||||
|
||||
/*
|
||||
* DFI external functions
|
||||
*/
|
||||
extern void dfi_mem_read(u64 addr, void *buf, size_t cnt);
|
||||
extern int dfi_mem_read_rc(u64 addr, void *buf, size_t cnt);
|
||||
extern void dfi_mem_phys_read(u64 addr, void *buf, size_t cnt);
|
||||
|
||||
void dfi_mem_map_print(bool verbose);
|
||||
|
||||
void dfi_mem_unmap(u64 start, u64 size);
|
||||
void dfi_mem_map(u64 start, u64 size, u64 start_phys);
|
||||
|
||||
int dfi_mem_chunk_init(void);
|
||||
void dfi_mem_chunk_deinit(void);
|
||||
|
||||
#endif /* DFI_MEM_CHUNK_H */
|
||||
Reference in New Issue
Block a user