busybox/miscutils/devmem.c
<<
>>
Prefs
   1/*
   2 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
   3 *  Copyright (C) 2000, Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
   4 *  Copyright (C) 2008, BusyBox Team. -solar 4/26/08
   5 */
   6
   7#include "libbb.h"
   8
   9int devmem_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  10int devmem_main(int argc UNUSED_PARAM, char **argv)
  11{
  12        void *map_base, *virt_addr;
  13        uint64_t read_result;
  14        uint64_t writeval = writeval; /* for compiler */
  15        off_t target;
  16        unsigned page_size = getpagesize();
  17        int fd;
  18        int width = 8 * sizeof(int);
  19
  20        /* devmem ADDRESS [WIDTH [VALUE]] */
  21// TODO: options?
  22// -r: read and output only the value in hex, with 0x prefix
  23// -w: write only, no reads before or after, and no output
  24// or make this behavior default?
  25// Let's try this and see how users react.
  26
  27        /* ADDRESS */
  28        if (!argv[1])
  29                bb_show_usage();
  30        errno = 0;
  31        target = bb_strtoull(argv[1], NULL, 0); /* allows hex, oct etc */
  32
  33        /* WIDTH */
  34        if (argv[2]) {
  35                if (isdigit(argv[2][0]) || argv[2][1])
  36                        width = xatou(argv[2]);
  37                else {
  38                        static const char bhwl[] ALIGN1 = "bhwl";
  39                        static const uint8_t sizes[] ALIGN1 = {
  40                                8 * sizeof(char),
  41                                8 * sizeof(short),
  42                                8 * sizeof(int),
  43                                8 * sizeof(long),
  44                                0 /* bad */
  45                        };
  46                        width = strchrnul(bhwl, (argv[2][0] | 0x20)) - bhwl;
  47                        width = sizes[width];
  48                }
  49                /* VALUE */
  50                if (argv[3])
  51                        writeval = bb_strtoull(argv[3], NULL, 0);
  52        } else { /* argv[2] == NULL */
  53                /* make argv[3] to be a valid thing to use */
  54                argv--;
  55        }
  56        if (errno)
  57                bb_show_usage(); /* bb_strtouXX failed */
  58
  59        fd = xopen("/dev/mem", argv[3] ? (O_RDWR | O_SYNC) : (O_RDONLY | O_SYNC));
  60        map_base = mmap(NULL,
  61                        page_size * 2 /* in case value spans page */,
  62                        argv[3] ? (PROT_READ | PROT_WRITE) : PROT_READ,
  63                        MAP_SHARED,
  64                        fd,
  65                        target & ~(off_t)(page_size - 1));
  66        if (map_base == MAP_FAILED)
  67                bb_perror_msg_and_die("mmap");
  68
  69//      printf("Memory mapped at address %p.\n", map_base);
  70
  71        virt_addr = (char*)map_base + (target & (page_size - 1));
  72
  73        if (!argv[3]) {
  74                switch (width) {
  75                case 8:
  76                        read_result = *(volatile uint8_t*)virt_addr;
  77                        break;
  78                case 16:
  79                        read_result = *(volatile uint16_t*)virt_addr;
  80                        break;
  81                case 32:
  82                        read_result = *(volatile uint32_t*)virt_addr;
  83                        break;
  84                case 64:
  85                        read_result = *(volatile uint64_t*)virt_addr;
  86                        break;
  87                default:
  88                        bb_error_msg_and_die("bad width");
  89                }
  90//              printf("Value at address 0x%"OFF_FMT"X (%p): 0x%llX\n",
  91//                      target, virt_addr,
  92//                      (unsigned long long)read_result);
  93                /* Zero-padded output shows the width of access just done */
  94                printf("0x%0*llX\n", (width >> 2), (unsigned long long)read_result);
  95        } else {
  96                switch (width) {
  97                case 8:
  98                        *(volatile uint8_t*)virt_addr = writeval;
  99//                      read_result = *(volatile uint8_t*)virt_addr;
 100                        break;
 101                case 16:
 102                        *(volatile uint16_t*)virt_addr = writeval;
 103//                      read_result = *(volatile uint16_t*)virt_addr;
 104                        break;
 105                case 32:
 106                        *(volatile uint32_t*)virt_addr = writeval;
 107//                      read_result = *(volatile uint32_t*)virt_addr;
 108                        break;
 109                case 64:
 110                        *(volatile uint64_t*)virt_addr = writeval;
 111//                      read_result = *(volatile uint64_t*)virt_addr;
 112                        break;
 113                default:
 114                        bb_error_msg_and_die("bad width");
 115                }
 116//              printf("Written 0x%llX; readback 0x%llX\n",
 117//                              (unsigned long long)writeval,
 118//                              (unsigned long long)read_result);
 119        }
 120
 121        if (ENABLE_FEATURE_CLEAN_UP) {
 122                if (munmap(map_base, page_size * 2) == -1)
 123                        bb_perror_msg_and_die("munmap");
 124                close(fd);
 125        }
 126
 127        return EXIT_SUCCESS;
 128}
 129