devmem.c 3.8 KB

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