1*cf5a6c84SAndroid Build Coastguard Worker /* devmem.c - Access physical addresses
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2019 The Android Open Source Project
4*cf5a6c84SAndroid Build Coastguard Worker
5*cf5a6c84SAndroid Build Coastguard Worker USE_DEVMEM(NEWTOY(devmem, "<1(no-sync)(no-mmap)f:", TOYFLAG_USR|TOYFLAG_SBIN))
6*cf5a6c84SAndroid Build Coastguard Worker
7*cf5a6c84SAndroid Build Coastguard Worker config DEVMEM
8*cf5a6c84SAndroid Build Coastguard Worker bool "devmem"
9*cf5a6c84SAndroid Build Coastguard Worker default y
10*cf5a6c84SAndroid Build Coastguard Worker help
11*cf5a6c84SAndroid Build Coastguard Worker usage: devmem [-f FILE] ADDR [WIDTH [DATA...]]
12*cf5a6c84SAndroid Build Coastguard Worker
13*cf5a6c84SAndroid Build Coastguard Worker Read/write physical addresses. WIDTH is 1, 2, 4, or 8 bytes (default 4).
14*cf5a6c84SAndroid Build Coastguard Worker Prefix ADDR with 0x for hexadecimal, output is in same base as address.
15*cf5a6c84SAndroid Build Coastguard Worker
16*cf5a6c84SAndroid Build Coastguard Worker -f FILE File to operate on (default /dev/mem)
17*cf5a6c84SAndroid Build Coastguard Worker --no-sync Don't open the file with O_SYNC (for cached access)
18*cf5a6c84SAndroid Build Coastguard Worker --no-mmap Don't mmap the file
19*cf5a6c84SAndroid Build Coastguard Worker */
20*cf5a6c84SAndroid Build Coastguard Worker
21*cf5a6c84SAndroid Build Coastguard Worker #define FOR_devmem
22*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
23*cf5a6c84SAndroid Build Coastguard Worker
GLOBALS(char * f;)24*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
25*cf5a6c84SAndroid Build Coastguard Worker char *f;
26*cf5a6c84SAndroid Build Coastguard Worker )
27*cf5a6c84SAndroid Build Coastguard Worker
28*cf5a6c84SAndroid Build Coastguard Worker unsigned long xatolu(char *str, int bytes)
29*cf5a6c84SAndroid Build Coastguard Worker {
30*cf5a6c84SAndroid Build Coastguard Worker char *end = str;
31*cf5a6c84SAndroid Build Coastguard Worker unsigned long lu;
32*cf5a6c84SAndroid Build Coastguard Worker
33*cf5a6c84SAndroid Build Coastguard Worker errno = 0;
34*cf5a6c84SAndroid Build Coastguard Worker lu = strtoul(str, &end, 0);
35*cf5a6c84SAndroid Build Coastguard Worker // Report out of range values as errors rather than truncating.
36*cf5a6c84SAndroid Build Coastguard Worker if (errno == ERANGE || lu > (~0UL)>>(sizeof(long)-bytes)*8)
37*cf5a6c84SAndroid Build Coastguard Worker error_exit("%s>%d bytes", str, bytes);
38*cf5a6c84SAndroid Build Coastguard Worker if (*end || errno) perror_exit("bad %s", str);
39*cf5a6c84SAndroid Build Coastguard Worker
40*cf5a6c84SAndroid Build Coastguard Worker return lu;
41*cf5a6c84SAndroid Build Coastguard Worker }
42*cf5a6c84SAndroid Build Coastguard Worker
devmem_main(void)43*cf5a6c84SAndroid Build Coastguard Worker void devmem_main(void)
44*cf5a6c84SAndroid Build Coastguard Worker {
45*cf5a6c84SAndroid Build Coastguard Worker int ii, writing = toys.optc > 2, bytes = 4, fd;
46*cf5a6c84SAndroid Build Coastguard Worker unsigned long data QUIET, map_len QUIET,
47*cf5a6c84SAndroid Build Coastguard Worker addr = xatolu(*toys.optargs, sizeof(long));
48*cf5a6c84SAndroid Build Coastguard Worker void *map QUIET, *p QUIET;
49*cf5a6c84SAndroid Build Coastguard Worker
50*cf5a6c84SAndroid Build Coastguard Worker // WIDTH?
51*cf5a6c84SAndroid Build Coastguard Worker if (toys.optc>1) {
52*cf5a6c84SAndroid Build Coastguard Worker char *sizes = sizeof(long)==8 ? "1248" : "124";
53*cf5a6c84SAndroid Build Coastguard Worker
54*cf5a6c84SAndroid Build Coastguard Worker if ((ii = stridx(sizes, *toys.optargs[1]))==-1 || toys.optargs[1][1])
55*cf5a6c84SAndroid Build Coastguard Worker error_exit("bad width: %s", toys.optargs[1]);
56*cf5a6c84SAndroid Build Coastguard Worker bytes = 1<<ii;
57*cf5a6c84SAndroid Build Coastguard Worker }
58*cf5a6c84SAndroid Build Coastguard Worker
59*cf5a6c84SAndroid Build Coastguard Worker // Map in just enough.
60*cf5a6c84SAndroid Build Coastguard Worker if (CFG_TOYBOX_FORK) {
61*cf5a6c84SAndroid Build Coastguard Worker fd = xopen(TT.f ? : "/dev/mem", O_RDWR*writing+O_SYNC*!FLAG(no_sync));
62*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(no_mmap)) xlseek(fd, addr, SEEK_SET);
63*cf5a6c84SAndroid Build Coastguard Worker else {
64*cf5a6c84SAndroid Build Coastguard Worker unsigned long long page_size = sysconf(_SC_PAGESIZE)-1, map_off;
65*cf5a6c84SAndroid Build Coastguard Worker
66*cf5a6c84SAndroid Build Coastguard Worker map_off = addr & ~page_size;
67*cf5a6c84SAndroid Build Coastguard Worker map_len = addr + (writing ? (toys.optc - 2) * bytes : bytes) - map_off;
68*cf5a6c84SAndroid Build Coastguard Worker map = xmmap(0, map_len, writing ? PROT_WRITE : PROT_READ, MAP_SHARED, fd,
69*cf5a6c84SAndroid Build Coastguard Worker map_off);
70*cf5a6c84SAndroid Build Coastguard Worker p = map+(addr&page_size);
71*cf5a6c84SAndroid Build Coastguard Worker close(fd);
72*cf5a6c84SAndroid Build Coastguard Worker }
73*cf5a6c84SAndroid Build Coastguard Worker } else p = (void *)addr;
74*cf5a6c84SAndroid Build Coastguard Worker
75*cf5a6c84SAndroid Build Coastguard Worker // Not using peek()/poke() because registers care about size of read/write.
76*cf5a6c84SAndroid Build Coastguard Worker if (writing) {
77*cf5a6c84SAndroid Build Coastguard Worker for (ii = 2; ii<toys.optc; ii++) {
78*cf5a6c84SAndroid Build Coastguard Worker data = xatolu(toys.optargs[ii], bytes);
79*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(no_mmap)) xwrite(fd, &data, bytes);
80*cf5a6c84SAndroid Build Coastguard Worker else {
81*cf5a6c84SAndroid Build Coastguard Worker if (bytes==1) *(char *)p = data;
82*cf5a6c84SAndroid Build Coastguard Worker else if (bytes==2) *(unsigned short *)p = data;
83*cf5a6c84SAndroid Build Coastguard Worker else if (bytes==4) *(unsigned int *)p = data;
84*cf5a6c84SAndroid Build Coastguard Worker else if (sizeof(long)==8 && bytes==8) *(unsigned long *)p = data;
85*cf5a6c84SAndroid Build Coastguard Worker p += bytes;
86*cf5a6c84SAndroid Build Coastguard Worker }
87*cf5a6c84SAndroid Build Coastguard Worker }
88*cf5a6c84SAndroid Build Coastguard Worker } else {
89*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(no_mmap)) xread(fd, &data, bytes);
90*cf5a6c84SAndroid Build Coastguard Worker else {
91*cf5a6c84SAndroid Build Coastguard Worker if (bytes==1) data = *(char *)p;
92*cf5a6c84SAndroid Build Coastguard Worker else if (bytes==2) data = *(unsigned short *)p;
93*cf5a6c84SAndroid Build Coastguard Worker else if (bytes==4) data = *(unsigned int *)p;
94*cf5a6c84SAndroid Build Coastguard Worker else if (sizeof(long)==8 && bytes==8) data = *(unsigned long *)p;
95*cf5a6c84SAndroid Build Coastguard Worker }
96*cf5a6c84SAndroid Build Coastguard Worker printf((!strchr(*toys.optargs, 'x')) ? "%0*ld\n" : "0x%0*lx\n",
97*cf5a6c84SAndroid Build Coastguard Worker bytes*2, data);
98*cf5a6c84SAndroid Build Coastguard Worker }
99*cf5a6c84SAndroid Build Coastguard Worker
100*cf5a6c84SAndroid Build Coastguard Worker if (CFG_TOYBOX_FORK) {
101*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(no_mmap)) close(fd);
102*cf5a6c84SAndroid Build Coastguard Worker else munmap(map, map_len);
103*cf5a6c84SAndroid Build Coastguard Worker }
104*cf5a6c84SAndroid Build Coastguard Worker }
105