1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12#include <utils/debug.h>
13#include <stdint.h>
14#include <utils/arith.h>
15#include <utils/util.h>
16#include <utils/zf_log.h>
17#include <string.h>
18#include <inttypes.h>
19
20#define MD_BYTES_PER_LINE (sizeof(uint32_t) * 4)
21#define MD_GROUPING       4
22
23static void
24md_print_line(void* address, int word_size)
25{
26    uint8_t line[MD_BYTES_PER_LINE];
27    int num_objects = MD_BYTES_PER_LINE / word_size;
28    int object;
29    printf("%p: ", address);
30    for (object = 0; object < num_objects; object++) {
31        int object_offset = object * word_size;
32        if (MD_GROUPING > word_size && object % ((MD_GROUPING) / word_size) == 0) {
33            putchar(' ');
34        }
35        switch (word_size) {
36        case 1: {
37            uint8_t temp = *(volatile uint8_t*)(address + object_offset);
38            printf("0x%02x ", temp);
39            memcpy(&line[object_offset], &temp, sizeof(temp));
40            break;
41        }
42        case 2: {
43            uint16_t temp = *(volatile uint16_t*)(address + object_offset);
44            printf("0x%04x ", temp);
45            memcpy(&line[object_offset], &temp, sizeof(temp));
46            break;
47        }
48        case 4: {
49            uint32_t temp = *(volatile uint32_t*)(address + object_offset);
50            printf("0x%08x ", temp);
51            memcpy(&line[object_offset], &temp, sizeof(temp));
52            break;
53        }
54        case 8: {
55            uint64_t temp = *(volatile uint64_t*)(address + object_offset);
56            printf("0x%016"PRIx64" ", temp);
57            memcpy(&line[object_offset], &temp, sizeof(temp));
58            break;
59        }
60        }
61    }
62    /* Print ASCII string */
63    printf("    |");
64    for (object = 0; object < MD_BYTES_PER_LINE; object++) {
65        if (line[object] < 32 || line[object] > 126) {
66            putchar('.');
67        } else {
68            putchar(line[object]);
69        }
70    }
71    printf("|\n");
72}
73
74void
75utils_memory_dump(void* address, size_t bytes, int word_size)
76{
77    void* a;
78    if (word_size == 1 || word_size == 2 || word_size == 4 || word_size == 8) {
79        /* Notify the caller if 'bytes' is not a multple of MD_BYTES_PER_LINE */
80        if (bytes % MD_BYTES_PER_LINE) {
81            int extra_bytes = MD_BYTES_PER_LINE - (bytes % MD_BYTES_PER_LINE);
82            LOG_INFO("Rounding displayed bytes from %zu up to %zu", bytes, bytes + extra_bytes);
83            bytes += extra_bytes;
84        }
85        /* Print each line */
86        for (a = address; a < address + bytes; a += MD_BYTES_PER_LINE) {
87            md_print_line(a, word_size);
88        }
89    } else {
90        LOG_ERROR("Invalid word size (%d). Valid options are [1, 2, 4, 8]", word_size);
91    }
92}
93