summaryrefslogtreecommitdiffstats
path: root/common/memory_display.c
blob: fbb8bbb6faa711037a44cacc52a63f49b47f35c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#include <common.h>
#include <errno.h>
#include <abort.h>

#define DISP_LINE_LEN	16


int __pr_memory_display(int level, const void *addr, loff_t offs, unsigned nbytes,
			int size, int swab, const char *fmt, ...)
{
	unsigned long linebytes, i;
	unsigned char *cp;
	unsigned char line[sizeof("00000000: 0000 0000 0000 0000  0000 0000 0000 0000            ................")];
	struct va_format vaf;
	int ret;
	va_list args;

	va_start(args, fmt);

	vaf.fmt = fmt;
	vaf.va = &args;

	/* Print the lines.
	 *
	 * We buffer all read data, so we can make sure data is read only
	 * once, and all accesses are with the specified bus width.
	 */
	do {
		unsigned char linebuf[DISP_LINE_LEN];
		uint64_t *ullp = (uint64_t *)linebuf;
		uint32_t *uip = (uint32_t *)linebuf;
		uint16_t *usp = (uint16_t *)linebuf;
		uint8_t *ucp = (uint8_t *)linebuf;
		unsigned char *pos = line;

		pos += sprintf(pos, "%08llx:", offs);
		linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;

		for (i = 0; i < linebytes; i += size) {
			if (size == 8) {
				uint64_t res;
				data_abort_mask();
				res = *((uint64_t *)addr);
				if (swab)
					res = __swab64(res);
				if (data_abort_unmask()) {
					res = 0xffffffffffffffffULL;
					pos += sprintf(pos, " xxxxxxxxxxxxxxxx");
				} else {
					pos += sprintf(pos, " %016llx", res);
				}
				*ullp++ = res;
			} else if (size == 4) {
				uint32_t res;
				data_abort_mask();
				res = *((uint32_t *)addr);
				if (swab)
					res = __swab32(res);
				if (data_abort_unmask()) {
					res = 0xffffffff;
					pos += sprintf(pos, " xxxxxxxx");
				} else {
					pos += sprintf(pos, " %08x", res);
				}
				*uip++ = res;
			} else if (size == 2) {
				uint16_t res;
				data_abort_mask();
				res = *((uint16_t *)addr);
				if (swab)
					res = __swab16(res);
				if (i > 1 && i % 8 == 0)
					pos += sprintf(pos, " ");
				if (data_abort_unmask()) {
					res = 0xffff;
					pos += sprintf(pos, " xxxx");
				} else {
					pos += sprintf(pos, " %04x", res);
				}
				*usp++ = res;
			} else {
				uint8_t res;
				data_abort_mask();
				res = *((uint8_t *)addr);
				if (i > 1 && i % 8 == 0)
					pos += sprintf(pos, " ");
				if (data_abort_unmask()) {
					res = 0xff;
					pos += sprintf(pos, " xx");
				} else {
					pos += sprintf(pos, " %02x", res);
				}
				*ucp++ = res;
			}
			addr += size;
			offs += size;
		}

		pos += sprintf(pos, "%*s", (int)(61 - (pos - line)), "");

		cp = linebuf;
		for (i = 0; i < linebytes; i++) {
			if ((*cp < 0x20) || (*cp > 0x7e))
				sprintf(pos, ".");
			else
				sprintf(pos, "%c", *cp);
			pos++;
			cp++;
		}

		if (level >= MSG_EMERG)
			pr_print(level, "%pV%s\n", &vaf, line);
		else
			printf("%s\n", line);

		nbytes -= linebytes;
		if (ctrlc()) {
			ret = -EINTR;
			goto out;
		}

	} while (nbytes > 0);

	va_end(args);
	ret = 0;
out:

	return ret;
}

int memory_display(const void *addr, loff_t offs, unsigned nbytes,
		   int size, int swab)
{
	return pr_memory_display(-1, addr, offs, nbytes, size, swab);
}