diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-26 11:08:14 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-26 11:08:14 +0000 |
commit | c94fa5651a6c4f6b526de261e7480ce2c4e34aba (patch) | |
tree | f75161b60cffcec4acde0387618de3cd7b5cca52 /miscutils/devmem.c | |
parent | f3dcd3c30aa704a542b50357094d037f976be3ce (diff) | |
download | busybox-w32-c94fa5651a6c4f6b526de261e7480ce2c4e34aba.tar.gz busybox-w32-c94fa5651a6c4f6b526de261e7480ce2c4e34aba.tar.bz2 busybox-w32-c94fa5651a6c4f6b526de261e7480ce2c4e34aba.zip |
devmem: new applet
Diffstat (limited to 'miscutils/devmem.c')
-rw-r--r-- | miscutils/devmem.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/miscutils/devmem.c b/miscutils/devmem.c new file mode 100644 index 000000000..8b8edbe7c --- /dev/null +++ b/miscutils/devmem.c | |||
@@ -0,0 +1,123 @@ | |||
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 | |||
9 | #define DEVMEM_MAP_SIZE 4096 | ||
10 | #define DEVMEM_MAP_MASK (off_t)(DEVMEM_MAP_SIZE - 1) | ||
11 | |||
12 | int devmem_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
13 | int devmem_main(int argc UNUSED_PARAM, char **argv) | ||
14 | { | ||
15 | void *map_base, *virt_addr; | ||
16 | uint64_t read_result; | ||
17 | uint64_t writeval = writeval; /* for compiler */ | ||
18 | off_t target; | ||
19 | int fd; | ||
20 | int width = 8 * sizeof(int); | ||
21 | |||
22 | /* devmem ADDRESS [WIDTH [VALUE]] */ | ||
23 | |||
24 | /* ADDRESS */ | ||
25 | if (!argv[1]) | ||
26 | bb_show_usage(); | ||
27 | errno = 0; | ||
28 | target = bb_strtoull(argv[1], NULL, 0); /* allows hex, oct etc */ | ||
29 | |||
30 | /* WIDTH */ | ||
31 | if (argv[2]) { | ||
32 | if (isdigit(argv[2][0]) || argv[2][1]) | ||
33 | width = xatou(argv[2]); | ||
34 | else { | ||
35 | static const char bhwl[] ALIGN1 = "bhwl"; | ||
36 | static const uint8_t sizes[] ALIGN1 = { | ||
37 | 8 * sizeof(char), | ||
38 | 8 * sizeof(short), | ||
39 | 8 * sizeof(int), | ||
40 | 8 * sizeof(long), | ||
41 | 0 /* bad */ | ||
42 | }; | ||
43 | width = strchrnul(bhwl, (argv[2][0] | 0x20)) - bhwl; | ||
44 | width = sizes[width]; | ||
45 | } | ||
46 | /* VALUE */ | ||
47 | if (argv[3]) | ||
48 | writeval = bb_strtoull(argv[3], NULL, 0); | ||
49 | } else { /* argv[2] == NULL */ | ||
50 | /* make argv[3] to be a valid thing to use */ | ||
51 | argv--; | ||
52 | } | ||
53 | if (errno) | ||
54 | bb_show_usage(); /* bb_strtouXX failed */ | ||
55 | |||
56 | fd = xopen("/dev/mem", argv[3] ? (O_RDWR | O_SYNC) : (O_RDONLY | O_SYNC)); | ||
57 | |||
58 | map_base = mmap(NULL, | ||
59 | DEVMEM_MAP_SIZE * 2 /* in case value spans page */, | ||
60 | argv[3] ? (PROT_READ | PROT_WRITE) : PROT_READ, | ||
61 | MAP_SHARED, | ||
62 | fd, | ||
63 | target & ~DEVMEM_MAP_MASK); | ||
64 | if (map_base == MAP_FAILED) | ||
65 | bb_perror_msg_and_die("mmap"); | ||
66 | |||
67 | // printf("Memory mapped at address %p.\n", map_base); | ||
68 | |||
69 | virt_addr = (char*)map_base + (target & DEVMEM_MAP_MASK); | ||
70 | |||
71 | switch (width) { | ||
72 | case 8: | ||
73 | read_result = *(volatile uint8_t*)virt_addr; | ||
74 | break; | ||
75 | case 16: | ||
76 | read_result = *(volatile uint16_t*)virt_addr; | ||
77 | break; | ||
78 | case 32: | ||
79 | read_result = *(volatile uint32_t*)virt_addr; | ||
80 | break; | ||
81 | case 64: | ||
82 | read_result = *(volatile uint64_t*)virt_addr; | ||
83 | break; | ||
84 | default: | ||
85 | bb_error_msg_and_die("bad width"); | ||
86 | } | ||
87 | |||
88 | printf("Value at address 0x%"OFF_FMT"X (%p): 0x%llX\n", | ||
89 | target, virt_addr, | ||
90 | (unsigned long long)read_result); | ||
91 | |||
92 | if (argv[3]) { | ||
93 | switch (width) { | ||
94 | case 8: | ||
95 | *(volatile uint8_t*)virt_addr = writeval; | ||
96 | read_result = *(volatile uint8_t*)virt_addr; | ||
97 | break; | ||
98 | case 16: | ||
99 | *(volatile uint16_t*)virt_addr = writeval; | ||
100 | read_result = *(volatile uint16_t*)virt_addr; | ||
101 | break; | ||
102 | case 32: | ||
103 | *(volatile uint32_t*)virt_addr = writeval; | ||
104 | read_result = *(volatile uint32_t*)virt_addr; | ||
105 | break; | ||
106 | case 64: | ||
107 | *(volatile uint64_t*)virt_addr = writeval; | ||
108 | read_result = *(volatile uint64_t*)virt_addr; | ||
109 | break; | ||
110 | } | ||
111 | printf("Written 0x%llX; readback 0x%llX\n", | ||
112 | (unsigned long long)writeval, | ||
113 | (unsigned long long)read_result); | ||
114 | } | ||
115 | |||
116 | if (ENABLE_FEATURE_CLEAN_UP) { | ||
117 | if (munmap(map_base, DEVMEM_MAP_SIZE) == -1) | ||
118 | bb_perror_msg_and_die("munmap"); | ||
119 | close(fd); | ||
120 | } | ||
121 | |||
122 | return EXIT_SUCCESS; | ||
123 | } | ||