xref: /third_party/toybox/toys/other/devmem.c (revision 0f66f451)
1/* devmem.c - Access physical addresses
2 *
3 * Copyright 2019 The Android Open Source Project
4
5USE_DEVMEM(NEWTOY(devmem, "<1>3", TOYFLAG_USR|TOYFLAG_BIN))
6
7config DEVMEM
8  bool "devmem"
9  default y
10  help
11    usage: devmem ADDR [WIDTH [DATA]]
12
13    Read/write physical address. WIDTH is 1, 2, 4, or 8 bytes (default 4).
14    Prefix ADDR with 0x for hexadecimal, output is in same base as address.
15*/
16
17#define FOR_devmem
18#include "toys.h"
19
20void devmem_main(void)
21{
22  int writing = toys.optc == 3, page_size = getpagesize(), bytes = 4, fd;
23  unsigned long long addr = atolx(toys.optargs[0]), data = 0, map_off, map_len;
24  void *map, *p;
25
26  // WIDTH?
27  if (toys.optc>1) {
28    int i;
29
30    if (strlen(toys.optargs[1])!=1 || (i=stridx("1248", *toys.optargs[1]))==-1)
31      error_exit("bad width: %s", toys.optargs[1]);
32    bytes = 1<<i;
33  }
34
35  // DATA? Report out of range values as errors rather than truncating.
36  if (writing) data = atolx_range(toys.optargs[2], 0, (1ULL<<(8*bytes))-1);
37
38  // Map in just enough.
39  fd = xopen("/dev/mem", (writing ? O_RDWR : O_RDONLY) | O_SYNC);
40  map_off = addr & ~(page_size - 1);
41  map_len = (addr+bytes-map_off);
42  map = xmmap(NULL, map_len, writing ? PROT_WRITE : PROT_READ, MAP_SHARED, fd,
43      map_off);
44  p = map + (addr & (page_size - 1));
45  close(fd);
46
47  // Not using peek()/poke() because registers care about size of read/write
48  if (writing) {
49    if (bytes == 1) *(char *)p = data;
50    else if (bytes == 2) *(short *)p = data;
51    else if (bytes == 4) *(int *)p = data;
52    else if (bytes == 8) *(long long *)p = data;
53  } else {
54    if (bytes == 1) data = *(char *)p;
55    else if (bytes == 2) data = *(short *)p;
56    else if (bytes == 4) data = *(int *)p;
57    else if (bytes == 8) data = *(long long *)p;
58    printf("%#0*llx\n", bytes*2, data);
59  }
60
61  munmap(map, map_len);
62}
63