[PATCH v2] kmem: update n option to dump memory block
by Masayoshi Mizuma
From: Masayoshi Mizuma <m.mizuma(a)jp.fujitsu.com>
Update for the "kmem -n" option to also dump memory block.
Currently, "kmem -n" shows the memory section only. This
patch gets available the memory block as well if 'memory_block'
structure and 'memory_subsys' symbol exist.
The memory block information is useful to investigate memory
hot-plug issue.
Signed-off-by: Masayoshi Mizuma <m.mizuma(a)jp.fujitsu.com>
---
defs.h | 9 ++
memory.c | 286 +++++++++++++++++++++++++++++++++++++++++++++++++++---
symbols.c | 18 ++++
3 files changed, 299 insertions(+), 14 deletions(-)
diff --git a/defs.h b/defs.h
index 5b64bb7..20dd6a7 100644
--- a/defs.h
+++ b/defs.h
@@ -2049,6 +2049,15 @@ struct offset_table { /* stash of commonly-used offsets */
long pci_bus_self;
long device_kobj;
long kobject_name;
+ long memory_block_dev;
+ long memory_block_start_section_nr;
+ long memory_block_end_section_nr;
+ long memory_block_state;
+ long memory_block_nid;
+ long mem_section_pageblock_flags;
+ long bus_type_p;
+ long device_private_device;
+ long device_private_knode_bus;
};
struct size_table { /* stash of commonly-used sizes */
diff --git a/memory.c b/memory.c
index ea25047..9657c28 100644
--- a/memory.c
+++ b/memory.c
@@ -255,13 +255,14 @@ static void PG_slab_flag_init(void);
static ulong nr_blockdev_pages(void);
void sparse_mem_init(void);
void dump_mem_sections(int);
+void dump_memory_blocks(int);
void list_mem_sections(void);
ulong sparse_decode_mem_map(ulong, ulong);
char *read_mem_section(ulong);
ulong nr_to_section(ulong);
int valid_section(ulong);
int section_has_mem_map(ulong);
-ulong section_mem_map_addr(ulong);
+ulong section_mem_map_addr(ulong, int);
ulong valid_section_nr(ulong);
ulong pfn_to_map(ulong);
static int get_nodes_online(void);
@@ -5528,7 +5529,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
pc->curcmd_flags |= HEADER_PRINTED;
}
- pp = section_mem_map_addr(section);
+ pp = section_mem_map_addr(section, 0);
pp = sparse_decode_mem_map(pp, section_nr);
phys = (physaddr_t) section_nr * PAGES_PER_SECTION() * PAGESIZE();
section_size = PAGES_PER_SECTION();
@@ -13389,7 +13390,7 @@ is_page_ptr(ulong addr, physaddr_t *phys)
nr_mem_sections = vt->max_mem_section_nr+1;
for (nr = 0; nr < nr_mem_sections ; nr++) {
if ((sec_addr = valid_section_nr(nr))) {
- coded_mem_map = section_mem_map_addr(sec_addr);
+ coded_mem_map = section_mem_map_addr(sec_addr, 0);
mem_map = sparse_decode_mem_map(coded_mem_map, nr);
end_mem_map = mem_map + (PAGES_PER_SECTION() * SIZE(page));
@@ -16354,8 +16355,10 @@ dump_memory_nodes(int initialize)
vt->numnodes = n;
}
- if (IS_SPARSEMEM())
+ if (IS_SPARSEMEM()) {
dump_mem_sections(initialize);
+ dump_memory_blocks(initialize);
+ }
}
/*
@@ -17140,7 +17143,7 @@ section_has_mem_map(ulong addr)
}
ulong
-section_mem_map_addr(ulong addr)
+section_mem_map_addr(ulong addr, int raw)
{
char *mem_section;
ulong map;
@@ -17148,7 +17151,8 @@ section_mem_map_addr(ulong addr)
if ((mem_section = read_mem_section(addr))) {
map = ULONG(mem_section +
OFFSET(mem_section_section_mem_map));
- map &= SECTION_MAP_MASK;
+ if (!raw)
+ map &= SECTION_MAP_MASK;
return map;
}
return 0;
@@ -17179,7 +17183,7 @@ pfn_to_map(ulong pfn)
if (section_has_mem_map(section)) {
page_offset = pfn - section_nr_to_pfn(section_nr);
- coded_mem_map = section_mem_map_addr(section);
+ coded_mem_map = section_mem_map_addr(section, 0);
mem_map = sparse_decode_mem_map(coded_mem_map, section_nr) +
(page_offset * SIZE(page));
return mem_map;
@@ -17188,16 +17192,33 @@ pfn_to_map(ulong pfn)
return 0;
}
+static void
+fill_mem_section_state(ulong state, char *buf)
+{
+ int bufidx = 0;
+
+ memset(buf, 0, sizeof(*buf) * BUFSIZE);
+
+ if (state & SECTION_MARKED_PRESENT)
+ bufidx += sprintf(buf + bufidx, "%s", "P");
+ if (state & SECTION_HAS_MEM_MAP)
+ bufidx += sprintf(buf + bufidx, "%s", "M");
+ if (state & SECTION_IS_ONLINE)
+ bufidx += sprintf(buf + bufidx, "%s", "O");
+}
+
void
dump_mem_sections(int initialize)
{
ulong nr, max, addr;
ulong nr_mem_sections;
ulong coded_mem_map, mem_map, pfn;
+ char statebuf[BUFSIZE];
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
char buf4[BUFSIZE];
+ char buf5[BUFSIZE];
nr_mem_sections = NR_MEM_SECTIONS();
@@ -17212,19 +17233,23 @@ dump_mem_sections(int initialize)
fprintf(fp, "\n");
pad_line(fp, BITS32() ? 59 : 67, '-');
- fprintf(fp, "\n\nNR %s %s %s PFN\n",
+ fprintf(fp, "\n\nNR %s %s %s %s PFN\n",
mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "SECTION"),
mkstring(buf2, MAX(VADDR_PRLEN,strlen("CODED_MEM_MAP")),
CENTER|LJUST, "CODED_MEM_MAP"),
- mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "MEM_MAP"));
+ mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "MEM_MAP"),
+ mkstring(buf4, strlen("STATE"), CENTER, "STATE"));
for (nr = 0; nr < nr_mem_sections ; nr++) {
if ((addr = valid_section_nr(nr))) {
- coded_mem_map = section_mem_map_addr(addr);
+ coded_mem_map = section_mem_map_addr(addr, 0);
mem_map = sparse_decode_mem_map(coded_mem_map,nr);
pfn = section_nr_to_pfn(nr);
+ fill_mem_section_state(section_mem_map_addr(addr, 1),
+ statebuf);
- fprintf(fp, "%2ld %s %s %s %s\n",
+
+ fprintf(fp, "%2ld %s %s %s %s %s\n",
nr,
mkstring(buf1, VADDR_PRLEN,
CENTER|LONG_HEX, MKSTR(addr)),
@@ -17233,15 +17258,248 @@ dump_mem_sections(int initialize)
CENTER|LONG_HEX|RJUST, MKSTR(coded_mem_map)),
mkstring(buf3, VADDR_PRLEN,
CENTER|LONG_HEX|RJUST, MKSTR(mem_map)),
+ mkstring(buf4, strlen("STATE"), CENTER, statebuf),
pc->output_radix == 10 ?
- mkstring(buf4, VADDR_PRLEN,
+ mkstring(buf5, VADDR_PRLEN,
LONG_DEC|LJUST, MKSTR(pfn)) :
- mkstring(buf4, VADDR_PRLEN,
+ mkstring(buf5, VADDR_PRLEN,
LONG_HEX|LJUST, MKSTR(pfn)));
}
}
}
+#define MEM_ONLINE (1<<0)
+#define MEM_GOING_OFFLINE (1<<1)
+#define MEM_OFFLINE (1<<2)
+#define MEM_GOING_ONLINE (1<<3)
+#define MEM_CANCEL_ONLINE (1<<4)
+#define MEM_CANCEL_OFFLINE (1<<5)
+
+static void
+fill_memory_block_state(ulong memblock, char *buf)
+{
+ ulong state;
+
+ memset(buf, 0, sizeof(*buf) * BUFSIZE);
+
+ readmem(memblock + OFFSET(memory_block_state), KVADDR, &state,
+ sizeof(void *), "memory_block state", FAULT_ON_ERROR);
+
+ switch (state) {
+ case MEM_ONLINE:
+ sprintf(buf, "%s", "ONLINE");
+ break;
+ case MEM_GOING_OFFLINE:
+ sprintf(buf, "%s", "GOING_OFFLINE");
+ break;
+ case MEM_OFFLINE:
+ sprintf(buf, "%s", "OFFLINE");
+ break;
+ case MEM_GOING_ONLINE:
+ sprintf(buf, "%s", "GOING_ONLINE");
+ break;
+ case MEM_CANCEL_ONLINE:
+ sprintf(buf, "%s", "CANCEL_ONLINE");
+ break;
+ case MEM_CANCEL_OFFLINE:
+ sprintf(buf, "%s", "CANCEL_OFFLINE");
+ break;
+ default:
+ sprintf(buf, "%s", "UNKNOWN");
+ }
+}
+
+static ulong
+pfn_to_phys(ulong pfn)
+{
+ return pfn << PAGE_SHIFT;
+}
+
+static void
+fill_memory_block_name(ulong memblock, char *name)
+{
+ ulong kobj, value;
+
+ memset(name, 0, sizeof(*name) * BUFSIZE);
+
+ kobj = memblock + OFFSET(memory_block_dev) + OFFSET(device_kobj);
+
+ readmem(kobj + OFFSET(kobject_name),
+ KVADDR, &value, sizeof(void *), "kobject name",
+ FAULT_ON_ERROR);
+
+ read_string(value, name, BUFSIZE-1);
+}
+
+static void
+fill_memory_block_srange(ulong start_sec, ulong end_sec, char *srange)
+{
+ memset(srange, 0, sizeof(*srange) * BUFSIZE);
+
+ if (start_sec == end_sec)
+ sprintf(srange, "%lu", start_sec);
+ else
+ sprintf(srange, "%lu-%lu", start_sec, end_sec);
+}
+
+static void
+print_memory_block(ulong memory_block)
+{
+ ulong start_sec, end_sec, start_pfn, end_pfn, nid;
+ char statebuf[BUFSIZE];
+ char srangebuf[BUFSIZE];
+ char name[BUFSIZE];
+ char buf1[BUFSIZE];
+ char buf2[BUFSIZE];
+ char buf3[BUFSIZE];
+ char buf4[BUFSIZE];
+ char buf5[BUFSIZE];
+ char buf6[BUFSIZE];
+ char buf7[BUFSIZE];
+
+ readmem(memory_block + OFFSET(memory_block_start_section_nr), KVADDR,
+ &start_sec, sizeof(void *), "memory_block start_section_nr",
+ FAULT_ON_ERROR);
+ readmem(memory_block + OFFSET(memory_block_end_section_nr), KVADDR,
+ &end_sec, sizeof(void *), "memory_block end_section_nr",
+ FAULT_ON_ERROR);
+
+ start_pfn = section_nr_to_pfn(start_sec);
+ end_pfn = section_nr_to_pfn(end_sec + 1);
+ fill_memory_block_state(memory_block, statebuf);
+ fill_memory_block_name(memory_block, name);
+ fill_memory_block_srange(start_sec, end_sec, srangebuf);
+
+ if (MEMBER_EXISTS("memory_block", "nid")) {
+ readmem(memory_block + OFFSET(memory_block_nid), KVADDR, &nid,
+ sizeof(void *), "memory_block nid", FAULT_ON_ERROR);
+ fprintf(fp, " %s %s %s - %s %s %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(memory_block)),
+ mkstring(buf2, 12, CENTER, name),
+ mkstring(buf3, PADDR_PRLEN, RJUST|LONG_HEX,
+ MKSTR(pfn_to_phys(start_pfn))),
+ mkstring(buf4, PADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(pfn_to_phys(end_pfn) - 1)),
+ mkstring(buf5, strlen("NODE"), CENTER|LONG_DEC,
+ MKSTR(nid)),
+ mkstring(buf6, strlen("CANCEL_OFFLINE"), LJUST,
+ statebuf),
+ mkstring(buf7, 12, LJUST, srangebuf));
+ } else
+ fprintf(fp, " %s %s %s - %s %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(memory_block)),
+ mkstring(buf2, 10, CENTER, name),
+ mkstring(buf3, PADDR_PRLEN, RJUST|LONG_HEX,
+ MKSTR(pfn_to_phys(start_pfn))),
+ mkstring(buf4, PADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(pfn_to_phys(end_pfn) - 1)),
+ mkstring(buf5, strlen("CANCEL_OFFLINE"), LJUST,
+ statebuf),
+ mkstring(buf6, 12, LJUST, srangebuf));
+}
+
+static void
+init_memory_block_offset(void)
+{
+ MEMBER_OFFSET_INIT(bus_type_p, "bus_type", "p");
+ MEMBER_OFFSET_INIT(subsys_private_klist_devices,
+ "subsys_private", "klist_devices");
+ MEMBER_OFFSET_INIT(klist_k_list, "klist", "k_list");
+ MEMBER_OFFSET_INIT(klist_node_n_node, "klist_node", "n_node");
+ MEMBER_OFFSET_INIT(device_private_knode_bus,
+ "device_private", "knode_bus");
+ MEMBER_OFFSET_INIT(device_private_device, "device_private", "device");
+ MEMBER_OFFSET_INIT(memory_block_dev, "memory_block", "dev");
+ MEMBER_OFFSET_INIT(memory_block_start_section_nr,
+ "memory_block", "start_section_nr");
+ MEMBER_OFFSET_INIT(memory_block_end_section_nr,
+ "memory_block", "end_section_nr");
+ MEMBER_OFFSET_INIT(memory_block_state, "memory_block", "state");
+ if (MEMBER_EXISTS("memory_block", "nid"))
+ MEMBER_OFFSET_INIT(memory_block_nid, "memory_block", "nid");
+}
+
+static void
+init_memory_block(struct list_data *ld, int *klistcnt, ulong **klistbuf)
+{
+ ulong memory_subsys = symbol_value("memory_subsys");
+ ulong private, klist, start;
+
+ init_memory_block_offset();
+
+ readmem(memory_subsys + OFFSET(bus_type_p), KVADDR, &private,
+ sizeof(void *), "memory_subsys.private", FAULT_ON_ERROR);
+ klist = private + OFFSET(subsys_private_klist_devices) +
+ OFFSET(klist_k_list);
+ BZERO(ld, sizeof(struct list_data));
+
+ readmem(klist, KVADDR, &start,
+ sizeof(void *), "klist klist", FAULT_ON_ERROR);
+
+ ld->start = start;
+ ld->end = klist;
+ ld->list_head_offset = OFFSET(klist_node_n_node) +
+ OFFSET(device_private_knode_bus);
+ hq_open();
+ *klistcnt = do_list(ld);
+ *klistbuf = (ulong *)GETBUF(*klistcnt * sizeof(ulong));
+ *klistcnt = retrieve_list(*klistbuf, *klistcnt);
+ hq_close();
+}
+
+void
+dump_memory_blocks(int initialize)
+{
+ ulong memory_block, device;
+ ulong *klistbuf;
+ int klistcnt, i;
+ struct list_data list_data;
+ char mb_hdr[BUFSIZE];
+ char buf1[BUFSIZE];
+ char buf2[BUFSIZE];
+ char buf3[BUFSIZE];
+ char buf4[BUFSIZE];
+ char buf5[BUFSIZE];
+ char buf6[BUFSIZE];
+
+ if ((!STRUCT_EXISTS("memory_block")) ||
+ (!symbol_exists("memory_subsys")))
+ return;
+
+ if (initialize)
+ return;
+
+ init_memory_block(&list_data, &klistcnt, &klistbuf);
+
+ if (MEMBER_EXISTS("memory_block", "nid"))
+ sprintf(mb_hdr, "\n%s %s %s %s %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "MEM_BLOCK"),
+ mkstring(buf2, 10, CENTER, "NAME"),
+ mkstring(buf3, PADDR_PRLEN*2 + 2, CENTER, "PHYSICAL RANGE"),
+ mkstring(buf4, strlen("NODE"), CENTER, "NODE"),
+ mkstring(buf5, strlen("CANCEL_OFFLINE"), LJUST, "STATE"),
+ mkstring(buf6, 12, LJUST, "SECTIONS"));
+ else
+ sprintf(mb_hdr, "\n%s %s %s %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "MEM_BLOCK"),
+ mkstring(buf2, 10, CENTER, "NAME"),
+ mkstring(buf3, PADDR_PRLEN*2, CENTER, "PHYSICAL RANGE"),
+ mkstring(buf4, strlen("CANCEL_OFFLINE"), LJUST, "STATE"),
+ mkstring(buf5, 12, LJUST, "SECTIONS"));
+ fprintf(fp, "%s", mb_hdr);
+
+ for (i = 0; i < klistcnt; i++) {
+ readmem(klistbuf[i] + OFFSET(device_private_device), KVADDR,
+ &device, sizeof(void *), "device_private device",
+ FAULT_ON_ERROR);
+ memory_block = device - OFFSET(memory_block_dev);
+ print_memory_block(memory_block);
+ }
+ FREEBUF(klistbuf);
+}
+
void
list_mem_sections(void)
{
@@ -17251,7 +17509,7 @@ list_mem_sections(void)
for (nr = 0; nr <= nr_mem_sections ; nr++) {
if ((addr = valid_section_nr(nr))) {
- coded_mem_map = section_mem_map_addr(addr);
+ coded_mem_map = section_mem_map_addr(addr, 0);
fprintf(fp,
"nr=%ld section = %lx coded_mem_map=%lx pfn=%ld mem_map=%lx\n",
nr,
diff --git a/symbols.c b/symbols.c
index cb2174b..c5aab14 100644
--- a/symbols.c
+++ b/symbols.c
@@ -9938,6 +9938,18 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(tss_struct_ist));
fprintf(fp, " mem_section_section_mem_map: %ld\n",
OFFSET(mem_section_section_mem_map));
+ fprintf(fp, " mem_section_pageblock_flags: %ld\n",
+ OFFSET(mem_section_pageblock_flags));
+ fprintf(fp, " memory_block_dev: %ld\n",
+ OFFSET(memory_block_dev));
+ fprintf(fp, " memory_block_nid: %ld\n",
+ OFFSET(memory_block_nid));
+ fprintf(fp, " memory_block_start_section_nr: %ld\n",
+ OFFSET(memory_block_start_section_nr));
+ fprintf(fp, " memory_block_end_section_nr: %ld\n",
+ OFFSET(memory_block_end_section_nr));
+ fprintf(fp, " memory_block_state: %ld\n",
+ OFFSET(memory_block_state));
fprintf(fp, " vcpu_guest_context_user_regs: %ld\n",
OFFSET(vcpu_guest_context_user_regs));
@@ -10031,6 +10043,8 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(unwind_idx_addr));
fprintf(fp, " unwind_idx_insn: %ld\n",
OFFSET(unwind_idx_insn));
+ fprintf(fp, " bus_type_p: %ld\n",
+ OFFSET(bus_type_p));
fprintf(fp, " class_devices: %ld\n",
OFFSET(class_devices));
fprintf(fp, " class_p: %ld\n",
@@ -10041,6 +10055,10 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(device_knode_class));
fprintf(fp, " device_node: %ld\n",
OFFSET(device_node));
+ fprintf(fp, " device_private_device: %ld\n",
+ OFFSET(device_private_device));
+ fprintf(fp, " device_private_knode_bus: %ld\n",
+ OFFSET(device_private_knode_bus));
fprintf(fp, " gendisk_dev: %ld\n",
OFFSET(gendisk_dev));
fprintf(fp, " gendisk_kobj: %ld\n",
--
2.19.0
5 years, 11 months
[PATCH] kmem: update n option to dump memory block
by Masayoshi Mizuma
From: Masayoshi Mizuma <m.mizuma(a)jp.fujitsu.com>
Update for the "kmem -n" option to also dump memory block.
Currently, "kmem -n" shows the memory section only. This
patch gets available the memory block as well if 'memory_block'
structure and 'memory_subsys' symbol exist.
The memory block information is useful to investigate memory
hot-plug issue.
Signed-off-by: Masayoshi Mizuma <m.mizuma(a)jp.fujitsu.com>
---
defs.h | 8 ++
memory.c | 412 +++++++++++++++++++++++++++++++++++++++++++++++++------
2 files changed, 379 insertions(+), 41 deletions(-)
diff --git a/defs.h b/defs.h
index 5b64bb7..f707c64 100644
--- a/defs.h
+++ b/defs.h
@@ -2049,6 +2049,14 @@ struct offset_table { /* stash of commonly-used offsets */
long pci_bus_self;
long device_kobj;
long kobject_name;
+ long memory_block_dev;
+ long memory_block_start_section_nr;
+ long mem_section_pageblock_flags;
+ long memory_block_state;
+ long memory_block_nid;
+ long bus_type_p;
+ long device_private_device;
+ long device_private_knode_bus;
};
struct size_table { /* stash of commonly-used sizes */
diff --git a/memory.c b/memory.c
index ea25047..c7a4787 100644
--- a/memory.c
+++ b/memory.c
@@ -254,14 +254,16 @@ static void PG_reserved_flag_init(void);
static void PG_slab_flag_init(void);
static ulong nr_blockdev_pages(void);
void sparse_mem_init(void);
-void dump_mem_sections(int);
+void dump_mem_block_and_sections(int);
+void _dump_mem_block_and_sections(void);
+void dump_mem_sections(void);
void list_mem_sections(void);
ulong sparse_decode_mem_map(ulong, ulong);
char *read_mem_section(ulong);
ulong nr_to_section(ulong);
int valid_section(ulong);
int section_has_mem_map(ulong);
-ulong section_mem_map_addr(ulong);
+ulong section_mem_map_addr(ulong, int);
ulong valid_section_nr(ulong);
ulong pfn_to_map(ulong);
static int get_nodes_online(void);
@@ -5528,7 +5530,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
pc->curcmd_flags |= HEADER_PRINTED;
}
- pp = section_mem_map_addr(section);
+ pp = section_mem_map_addr(section, 0);
pp = sparse_decode_mem_map(pp, section_nr);
phys = (physaddr_t) section_nr * PAGES_PER_SECTION() * PAGESIZE();
section_size = PAGES_PER_SECTION();
@@ -13389,7 +13391,7 @@ is_page_ptr(ulong addr, physaddr_t *phys)
nr_mem_sections = vt->max_mem_section_nr+1;
for (nr = 0; nr < nr_mem_sections ; nr++) {
if ((sec_addr = valid_section_nr(nr))) {
- coded_mem_map = section_mem_map_addr(sec_addr);
+ coded_mem_map = section_mem_map_addr(sec_addr, 0);
mem_map = sparse_decode_mem_map(coded_mem_map, nr);
end_mem_map = mem_map + (PAGES_PER_SECTION() * SIZE(page));
@@ -16355,7 +16357,7 @@ dump_memory_nodes(int initialize)
}
if (IS_SPARSEMEM())
- dump_mem_sections(initialize);
+ dump_mem_block_and_sections(initialize);
}
/*
@@ -17140,7 +17142,7 @@ section_has_mem_map(ulong addr)
}
ulong
-section_mem_map_addr(ulong addr)
+section_mem_map_addr(ulong addr, int raw)
{
char *mem_section;
ulong map;
@@ -17148,7 +17150,8 @@ section_mem_map_addr(ulong addr)
if ((mem_section = read_mem_section(addr))) {
map = ULONG(mem_section +
OFFSET(mem_section_section_mem_map));
- map &= SECTION_MAP_MASK;
+ if (!raw)
+ map &= SECTION_MAP_MASK;
return map;
}
return 0;
@@ -17179,7 +17182,7 @@ pfn_to_map(ulong pfn)
if (section_has_mem_map(section)) {
page_offset = pfn - section_nr_to_pfn(section_nr);
- coded_mem_map = section_mem_map_addr(section);
+ coded_mem_map = section_mem_map_addr(section, 0);
mem_map = sparse_decode_mem_map(coded_mem_map, section_nr) +
(page_offset * SIZE(page));
return mem_map;
@@ -17188,16 +17191,365 @@ pfn_to_map(ulong pfn)
return 0;
}
-void
-dump_mem_sections(int initialize)
+struct memory_block_info {
+ ulong memory_block;
+ ulong start_sec;
+ ulong start_pfn;
+ ulong nid;
+ char state[24];
+ char name[32];
+};
+
+#define MIN_MEMORY_BLOCK_SIZE (1UL << _SECTION_SIZE_BITS)
+
+#define MEM_ONLINE (1<<0)
+#define MEM_GOING_OFFLINE (1<<1)
+#define MEM_OFFLINE (1<<2)
+#define MEM_GOING_ONLINE (1<<3)
+#define MEM_CANCEL_ONLINE (1<<4)
+#define MEM_CANCEL_OFFLINE (1<<5)
+
+static void
+fill_memory_block_state(ulong memblock, char *buf)
{
- ulong nr, max, addr;
- ulong nr_mem_sections;
+ ulong state;
+
+ memset(buf, 0, sizeof(*buf) * BUFSIZE);
+
+ readmem(memblock + OFFSET(memory_block_state), KVADDR, &state,
+ sizeof(void *), "memory_block state", FAULT_ON_ERROR);
+
+ switch (state) {
+ case MEM_ONLINE:
+ sprintf(buf, "%s", "ONLINE");
+ break;
+ case MEM_GOING_OFFLINE:
+ sprintf(buf, "%s", "GOING_OFFLINE");
+ break;
+ case MEM_OFFLINE:
+ sprintf(buf, "%s", "OFFLINE");
+ break;
+ case MEM_GOING_ONLINE:
+ sprintf(buf, "%s", "GOING_ONLINE");
+ break;
+ case MEM_CANCEL_ONLINE:
+ sprintf(buf, "%s", "CANCEL_ONLINE");
+ break;
+ case MEM_CANCEL_OFFLINE:
+ sprintf(buf, "%s", "CANCEL_OFFLINE");
+ break;
+ default:
+ sprintf(buf, "%s", "UNKNOWN");
+ }
+}
+
+static void
+fill_mem_section_state(ulong state, char *buf)
+{
+ int bufidx = 0, others = 0;
+
+ memset(buf, 0, sizeof(*buf) * BUFSIZE);
+
+#define printflag(X) sprintf(buf + bufidx, X, others++ ? "|" : "")
+
+ if (state & SECTION_MARKED_PRESENT)
+ bufidx += printflag("%sPRESENT");
+ if (state & SECTION_HAS_MEM_MAP)
+ bufidx += printflag("%sHAS_MEMMAP");
+ if (state & SECTION_IS_ONLINE)
+ bufidx += printflag("%sONLINE");
+}
+
+static ulong
+pfn_to_phys(ulong pfn)
+{
+ return pfn << PAGE_SHIFT;
+}
+
+static ulong
+get_memory_block_size(void)
+{
+ static ulong blksz;
+
+ if (blksz)
+ return blksz;
+
+ if (symbol_exists("memory_block_size_probed"))
+ get_symbol_data("memory_block_size_probed", sizeof(ulong),
+ &blksz);
+ else
+ blksz = MIN_MEMORY_BLOCK_SIZE;
+
+ return blksz;
+}
+
+static void
+fill_memory_block_name(ulong memblock, char *name)
+{
+ ulong kobj, value;
+
+ memset(name, 0, sizeof(*name) * BUFSIZE);
+
+ kobj = memblock + OFFSET(memory_block_dev) + OFFSET(device_kobj);
+
+ readmem(kobj + OFFSET(kobject_name),
+ KVADDR, &value, sizeof(void *), "kobject name",
+ FAULT_ON_ERROR);
+
+ read_string(value, name, BUFSIZE-1);
+}
+
+static void
+fill_memory_block_info(ulong mb, struct memory_block_info *mbi)
+{
+ ulong start, start_pfn, nid;
+ char statebuf[BUFSIZE];
+ char name[BUFSIZE];
+
+ readmem(mb + OFFSET(memory_block_start_section_nr), KVADDR,
+ &start, sizeof(void *), "memory_block start_section_nr",
+ FAULT_ON_ERROR);
+
+ start_pfn = section_nr_to_pfn(start);
+ fill_memory_block_state(mb, statebuf);
+ fill_memory_block_name(mb, name);
+
+ mbi->memory_block = mb;
+ mbi->start_sec = start;
+ mbi->start_pfn = start_pfn;
+ strncpy(mbi->state, statebuf, sizeof(mbi->state));
+ strncpy(mbi->name, name, sizeof(mbi->name));
+ if (MEMBER_EXISTS("memory_block", "nid")) {
+ readmem(mb + OFFSET(memory_block_nid), KVADDR, &nid,
+ sizeof(void *), "memory_block nid", FAULT_ON_ERROR);
+ mbi->nid = nid;
+ }
+}
+
+static void
+init_memory_block(void)
+{
+ MEMBER_OFFSET_INIT(bus_type_p, "bus_type", "p");
+ MEMBER_OFFSET_INIT(subsys_private_klist_devices,
+ "subsys_private", "klist_devices");
+ MEMBER_OFFSET_INIT(klist_k_list, "klist", "k_list");
+ MEMBER_OFFSET_INIT(klist_node_n_node, "klist_node", "n_node");
+ MEMBER_OFFSET_INIT(device_private_knode_bus,
+ "device_private", "knode_bus");
+ MEMBER_OFFSET_INIT(device_private_device, "device_private", "device");
+ MEMBER_OFFSET_INIT(memory_block_dev, "memory_block", "dev");
+ MEMBER_OFFSET_INIT(memory_block_start_section_nr,
+ "memory_block", "start_section_nr");
+ MEMBER_OFFSET_INIT(memory_block_state, "memory_block", "state");
+ if (MEMBER_EXISTS("memory_block", "nid"))
+ MEMBER_OFFSET_INIT(memory_block_nid, "memory_block", "nid");
+}
+
+static struct memory_block_info*
+parse_memory_block(void)
+{
+ ulong memory_subsys = symbol_value("memory_subsys");
+ ulong private, klist, memory_block, device;
+ ulong *klistbuf;
+ int klistcnt, i;
+ struct list_data list_data, *ld;
+ struct memory_block_info *memory_block_info;
+
+ init_memory_block();
+
+ readmem(memory_subsys + OFFSET(bus_type_p), KVADDR, &private,
+ sizeof(void *), "memory_subsys.private", FAULT_ON_ERROR);
+ klist = private + OFFSET(subsys_private_klist_devices) +
+ OFFSET(klist_k_list);
+ ld = &list_data;
+ BZERO(ld, sizeof(struct list_data));
+
+ ld->start = klist;
+ ld->end = klist;
+ ld->list_head_offset = OFFSET(klist_node_n_node) +
+ OFFSET(device_private_knode_bus);
+ hq_open();
+ klistcnt = do_list(ld);
+ klistbuf = (ulong *)GETBUF(klistcnt * sizeof(ulong));
+ klistcnt = retrieve_list(klistbuf, klistcnt);
+ hq_close();
+
+ memory_block_info = calloc(klistcnt + 1,
+ sizeof(struct memory_block_info));
+ if (!memory_block_info)
+ error(FATAL, "cannot allocate memory for memory_block_info\n");
+
+ for (i = 0; i < klistcnt; i++) {
+ readmem(klistbuf[i] + OFFSET(device_private_device), KVADDR,
+ &device, sizeof(void *), "device_private device",
+ FAULT_ON_ERROR);
+ memory_block = device - OFFSET(memory_block_dev);
+ fill_memory_block_info(memory_block, &memory_block_info[i]);
+ }
+ FREEBUF(klistbuf);
+
+ return memory_block_info;
+}
+
+static struct memory_block_info*
+get_memory_block_info(ulong pfn, struct memory_block_info *mbi_tbl)
+{
+ int i;
+
+ for (i = 0; mbi_tbl[i].memory_block != 0; i++)
+ if (pfn == mbi_tbl[i].start_pfn)
+ return &mbi_tbl[i];
+
+ return NULL;
+}
+
+
+static int
+is_memory_block_head(ulong pfn)
+{
+ ulong nr_pages = get_memory_block_size() / PAGE_SIZE;
+
+ return (pfn % nr_pages) == 0;
+}
+
+static void
+print_memory_block(ulong pfn, ulong nr_mb_pages, struct memory_block_info *mbi)
+{
+ char buf1[BUFSIZE];
+ char buf2[BUFSIZE];
+ char buf3[BUFSIZE];
+ char buf4[BUFSIZE];
+ char buf5[BUFSIZE];
+ char buf6[BUFSIZE];
+
+ if (MEMBER_EXISTS("memory_block", "nid"))
+ fprintf(fp, " %s %s %s - %s %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(mbi->memory_block)),
+ mkstring(buf2, 12, CENTER, mbi->name),
+ mkstring(buf3, PADDR_PRLEN, RJUST|LONG_HEX,
+ MKSTR(pfn_to_phys(pfn))),
+ mkstring(buf4, PADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(pfn_to_phys(pfn + nr_mb_pages) - 1)),
+ mkstring(buf5, strlen("NODE"), CENTER|LONG_DEC,
+ MKSTR(mbi->nid)),
+ mkstring(buf6, strlen("CANCEL_OFFLINE"), LJUST,
+ mbi->state));
+ else
+ fprintf(fp, " %s %s %s - %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(mbi->memory_block)),
+ mkstring(buf2, 10, CENTER, mbi->name),
+ mkstring(buf3, PADDR_PRLEN, RJUST|LONG_HEX,
+ MKSTR(pfn_to_phys(pfn))),
+ mkstring(buf4, PADDR_PRLEN, LJUST|LONG_HEX,
+ MKSTR(pfn_to_phys(pfn + nr_mb_pages) - 1)),
+ mkstring(buf5, strlen("CANCEL_OFFLINE"), LJUST,
+ mbi->state));
+}
+
+static void
+do_mem_block_and_sections(int print_memblk, struct memory_block_info *mbi_tbl)
+{
+ ulong nr, addr;
+ ulong nr_mem_sections, nr_mb_pages;
ulong coded_mem_map, mem_map, pfn;
+ struct memory_block_info *mbi;
+ char mb_hdr[BUFSIZE];
+ char ms_hdr[BUFSIZE];
+ char statebuf[BUFSIZE];
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
char buf4[BUFSIZE];
+ char buf5[BUFSIZE];
+
+ nr_mb_pages = PAGES_PER_SECTION() *
+ get_memory_block_size() / MIN_MEMORY_BLOCK_SIZE;
+
+ if (MEMBER_EXISTS("memory_block", "nid"))
+ sprintf(mb_hdr, "\n%s %s %s %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "MEM_BLOCK"),
+ mkstring(buf2, 10, CENTER, "NAME"),
+ mkstring(buf3, PADDR_PRLEN*2 + 2, CENTER, "PHYSICAL RANGE"),
+ mkstring(buf4, strlen("NODE"), CENTER, "NODE"),
+ mkstring(buf5, strlen("CANCEL_OFFLINE"), LJUST, "STATE"));
+ else
+ sprintf(mb_hdr, "\n%s %s %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "MEM_BLOCK"),
+ mkstring(buf2, 10, CENTER, "NAME"),
+ mkstring(buf3, PADDR_PRLEN*2, CENTER, "PHYSICAL RANGE"),
+ mkstring(buf4, strlen("CANCEL_OFFLINE"), LJUST, "STATE"));
+
+ sprintf(ms_hdr, "NR %s %s %s %s %s\n",
+ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "SECTION"),
+ mkstring(buf2, MAX(VADDR_PRLEN, strlen("CODED_MEM_MAP")),
+ CENTER|LJUST, "CODED_MEM_MAP"),
+ mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "MEM_MAP"),
+ mkstring(buf4, 12, CENTER, "PFN"),
+ mkstring(buf5, 12, LJUST, "STATE"));
+
+ if (!print_memblk)
+ fprintf(fp, "%s", ms_hdr);
+
+ nr_mem_sections = NR_MEM_SECTIONS();
+ for (nr = 0; nr < nr_mem_sections ; nr++) {
+ addr = valid_section_nr(nr);
+ if (addr) {
+ coded_mem_map = section_mem_map_addr(addr, 0);
+ mem_map = sparse_decode_mem_map(coded_mem_map, nr);
+ pfn = section_nr_to_pfn(nr);
+ fill_mem_section_state(section_mem_map_addr(addr, 1),
+ statebuf);
+
+ if ((print_memblk) && (is_memory_block_head(pfn))) {
+ mbi = get_memory_block_info(pfn, mbi_tbl);
+ fprintf(fp, "%s", mb_hdr);
+ print_memory_block(pfn, nr_mb_pages, mbi);
+ fprintf(fp, "%s", ms_hdr);
+ }
+
+ fprintf(fp, "%5ld %s %s %s %s %s\n",
+ nr,
+ mkstring(buf1, VADDR_PRLEN,
+ CENTER|LONG_HEX, MKSTR(addr)),
+ mkstring(buf2, MAX(VADDR_PRLEN,
+ strlen("CODED_MEM_MAP")),
+ CENTER|LONG_HEX|RJUST, MKSTR(coded_mem_map)),
+ mkstring(buf3, VADDR_PRLEN,
+ CENTER|LONG_HEX|RJUST, MKSTR(mem_map)),
+ pc->output_radix == 10 ?
+ mkstring(buf4, 12,
+ LONG_DEC|LJUST, MKSTR(pfn)) :
+ mkstring(buf4, 12,
+ LONG_HEX|LJUST, MKSTR(pfn)),
+ mkstring(buf5, 12, LJUST, statebuf));
+ }
+ }
+}
+
+
+void
+dump_mem_sections(void)
+{
+ do_mem_block_and_sections(0, NULL);
+}
+
+void
+_dump_mem_block_and_sections(void)
+{
+ struct memory_block_info *mbi_tbl;
+
+ mbi_tbl = parse_memory_block();
+ do_mem_block_and_sections(1, mbi_tbl);
+ free(mbi_tbl);
+}
+
+void
+dump_mem_block_and_sections(int initialize)
+{
+ ulong nr, max;
+ ulong nr_mem_sections;
nr_mem_sections = NR_MEM_SECTIONS();
@@ -17212,34 +17564,12 @@ dump_mem_sections(int initialize)
fprintf(fp, "\n");
pad_line(fp, BITS32() ? 59 : 67, '-');
- fprintf(fp, "\n\nNR %s %s %s PFN\n",
- mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "SECTION"),
- mkstring(buf2, MAX(VADDR_PRLEN,strlen("CODED_MEM_MAP")),
- CENTER|LJUST, "CODED_MEM_MAP"),
- mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "MEM_MAP"));
-
- for (nr = 0; nr < nr_mem_sections ; nr++) {
- if ((addr = valid_section_nr(nr))) {
- coded_mem_map = section_mem_map_addr(addr);
- mem_map = sparse_decode_mem_map(coded_mem_map,nr);
- pfn = section_nr_to_pfn(nr);
-
- fprintf(fp, "%2ld %s %s %s %s\n",
- nr,
- mkstring(buf1, VADDR_PRLEN,
- CENTER|LONG_HEX, MKSTR(addr)),
- mkstring(buf2, MAX(VADDR_PRLEN,
- strlen("CODED_MEM_MAP")),
- CENTER|LONG_HEX|RJUST, MKSTR(coded_mem_map)),
- mkstring(buf3, VADDR_PRLEN,
- CENTER|LONG_HEX|RJUST, MKSTR(mem_map)),
- pc->output_radix == 10 ?
- mkstring(buf4, VADDR_PRLEN,
- LONG_DEC|LJUST, MKSTR(pfn)) :
- mkstring(buf4, VADDR_PRLEN,
- LONG_HEX|LJUST, MKSTR(pfn)));
- }
- }
+ fprintf(fp, "\n\n");
+ if ((!STRUCT_EXISTS("memory_block")) ||
+ (!symbol_exists("memory_subsys")))
+ dump_mem_sections();
+ else
+ _dump_mem_block_and_sections();
}
void
@@ -17251,7 +17581,7 @@ list_mem_sections(void)
for (nr = 0; nr <= nr_mem_sections ; nr++) {
if ((addr = valid_section_nr(nr))) {
- coded_mem_map = section_mem_map_addr(addr);
+ coded_mem_map = section_mem_map_addr(addr, 0);
fprintf(fp,
"nr=%ld section = %lx coded_mem_map=%lx pfn=%ld mem_map=%lx\n",
nr,
--
2.19.0
5 years, 11 months
[PATCH 1/2] ppc64/opal: add a flag to determine if the kernel is running on OPAL firmware
by Hari Bathini
Add PPC64 specific flag for kernels running on platforms based on
OPAL firmware. Use this flag before processing commands specific to
OPAL based systems.
Signed-off-by: Hari Bathini <hbathini(a)linux.ibm.com>
---
defs.h | 8 ++++++++
ppc64.c | 36 ++++++++++++++++--------------------
2 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/defs.h b/defs.h
index 5b64bb7..567992e 100644
--- a/defs.h
+++ b/defs.h
@@ -5963,6 +5963,12 @@ struct ppc64_elf_prstatus {
#ifdef PPC64
+struct ppc64_opal {
+ uint64_t base;
+ uint64_t entry;
+ uint64_t size;
+};
+
struct ppc64_vmemmap {
unsigned long phys;
unsigned long virt;
@@ -6013,6 +6019,7 @@ struct machine_specific {
ulong _page_accessed;
int (*is_kvaddr)(ulong);
int (*is_vmaddr)(ulong);
+ struct ppc64_opal opal;
};
void ppc64_init(int);
@@ -6030,6 +6037,7 @@ void ppc64_dump_machdep_table(ulong);
* in the kernel is also 0x40.
*/
#define RADIX_MMU (0x40)
+#define OPAL_FW (0x80)
#define REGION_SHIFT (60UL)
#define REGION_ID(addr) (((unsigned long)(addr)) >> REGION_SHIFT)
diff --git a/ppc64.c b/ppc64.c
index ee2f76f..cf41765 100644
--- a/ppc64.c
+++ b/ppc64.c
@@ -241,6 +241,7 @@ struct machine_specific book3e_machine_specific = {
.is_vmaddr = book3e_is_vmaddr,
};
+#define SKIBOOT_BASE 0x30000000
/*
* Do all necessary machine-specific setup here. This is called several
@@ -362,6 +363,16 @@ ppc64_init(int when)
struct machine_specific *m = machdep->machspec;
/*
+ * To determine if the kernel was running on OPAL based platform,
+ * use struct opal, which is populated with relevant values.
+ */
+ if (symbol_exists("opal")) {
+ get_symbol_data("opal", sizeof(struct ppc64_opal), &(m->opal));
+ if (m->opal.base == SKIBOOT_BASE)
+ machdep->flags |= OPAL_FW;
+ }
+
+ /*
* On Power ISA 3.0 based server processors, a kernel can
* run with radix MMU or standard MMU. Set the flag,
* if it is radix MMU.
@@ -712,6 +723,8 @@ ppc64_dump_machdep_table(ulong arg)
fprintf(fp, "%sSWAP_ENTRY_L4", others++ ? "|" : "");
if (machdep->flags & RADIX_MMU)
fprintf(fp, "%sRADIX_MMU", others++ ? "|" : "");
+ if (machdep->flags & OPAL_FW)
+ fprintf(fp, "%sOPAL_FW", others++ ? "|" : "");
fprintf(fp, ")\n");
fprintf(fp, " kvbase: %lx\n", machdep->kvbase);
@@ -2828,7 +2841,6 @@ ppc64_get_smp_cpus(void)
*/
#define SKIBOOT_CONSOLE_DUMP_START 0x31000000
#define SKIBOOT_CONSOLE_DUMP_SIZE 0x100000
-#define SKIBOOT_BASE 0x30000000
#define ASCII_UNLIMITED ((ulong)(-1) >> 1)
void
@@ -2841,10 +2853,6 @@ opalmsg(void)
uint64_t u64;
uint64_t limit64;
};
- struct opal {
- unsigned long long base;
- unsigned long long entry;
- } opal;
int i, a;
size_t typesz;
void *location;
@@ -2856,25 +2864,13 @@ opalmsg(void)
long count = SKIBOOT_CONSOLE_DUMP_SIZE;
ulonglong addr = SKIBOOT_CONSOLE_DUMP_START;
+ if (!(machdep->flags & OPAL_FW))
+ error(FATAL, "dump was not captured on OPAL based system");
+
if (CRASHDEBUG(4))
fprintf(fp, "<addr: %llx count: %ld (%s)>\n",
addr, count, "PHYSADDR");
- /*
- * OPAL based platform check
- * struct opal of BSS section and hence default value will be ZERO(0)
- * opal_init() in the kernel initializes this structure based on
- * the platform. Use it as a key to determine whether the dump
- * was taken on an OPAL based system or not.
- */
- if (symbol_exists("opal")) {
- get_symbol_data("opal", sizeof(struct opal), &opal);
- if (opal.base != SKIBOOT_BASE)
- error(FATAL, "dump was captured on non-PowerNV machine");
- } else {
- error(FATAL, "dump was captured on non-PowerNV machine");
- }
-
BZERO(&mem, sizeof(struct memloc));
lost = typesz = per_line = 0;
location = NULL;
5 years, 11 months