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
7 //usage:#define devmem_trivial_usage
8 //usage: "ADDRESS [WIDTH [VALUE]]"
9 //usage:#define devmem_full_usage "\n\n"
10 //usage: "Read/write from physical address\n"
11 //usage: "\n ADDRESS Address to act upon"
12 //usage: "\n WIDTH Width (8/16/...)"
13 //usage: "\n VALUE Data to be written"
17 int devmem_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
18 int devmem_main(int argc UNUSED_PARAM
, char **argv
)
20 void *map_base
, *virt_addr
;
22 uint64_t writeval
= writeval
; /* for compiler */
24 unsigned page_size
, mapped_size
, offset_in_page
;
26 unsigned width
= 8 * sizeof(int);
28 /* devmem ADDRESS [WIDTH [VALUE]] */
30 // -r: read and output only the value in hex, with 0x prefix
31 // -w: write only, no reads before or after, and no output
32 // or make this behavior default?
33 // Let's try this and see how users react.
39 target
= bb_strtoull(argv
[1], NULL
, 0); /* allows hex, oct etc */
43 if (isdigit(argv
[2][0]) || argv
[2][1])
44 width
= xatou(argv
[2]);
46 static const char bhwl
[] ALIGN1
= "bhwl";
47 static const uint8_t sizes
[] ALIGN1
= {
54 width
= strchrnul(bhwl
, (argv
[2][0] | 0x20)) - bhwl
;
59 writeval
= bb_strtoull(argv
[3], NULL
, 0);
60 } else { /* argv[2] == NULL */
61 /* make argv[3] to be a valid thing to fetch */
65 bb_show_usage(); /* one of bb_strtouXX failed */
67 fd
= xopen("/dev/mem", argv
[3] ? (O_RDWR
| O_SYNC
) : (O_RDONLY
| O_SYNC
));
68 mapped_size
= page_size
= getpagesize();
69 offset_in_page
= (unsigned)target
& (page_size
- 1);
70 if (offset_in_page
+ width
> page_size
) {
71 /* This access spans pages.
72 * Must map two pages to make it possible: */
77 argv
[3] ? (PROT_READ
| PROT_WRITE
) : PROT_READ
,
80 target
& ~(off_t
)(page_size
- 1));
81 if (map_base
== MAP_FAILED
)
82 bb_perror_msg_and_die("mmap");
84 // printf("Memory mapped at address %p.\n", map_base);
86 virt_addr
= (char*)map_base
+ offset_in_page
;
91 read_result
= *(volatile uint8_t*)virt_addr
;
94 read_result
= *(volatile uint16_t*)virt_addr
;
97 read_result
= *(volatile uint32_t*)virt_addr
;
100 read_result
= *(volatile uint64_t*)virt_addr
;
103 bb_error_msg_and_die("bad width");
105 // printf("Value at address 0x%"OFF_FMT"X (%p): 0x%llX\n",
106 // target, virt_addr,
107 // (unsigned long long)read_result);
108 /* Zero-padded output shows the width of access just done */
109 printf("0x%0*llX\n", (width
>> 2), (unsigned long long)read_result
);
113 *(volatile uint8_t*)virt_addr
= writeval
;
114 // read_result = *(volatile uint8_t*)virt_addr;
117 *(volatile uint16_t*)virt_addr
= writeval
;
118 // read_result = *(volatile uint16_t*)virt_addr;
121 *(volatile uint32_t*)virt_addr
= writeval
;
122 // read_result = *(volatile uint32_t*)virt_addr;
125 *(volatile uint64_t*)virt_addr
= writeval
;
126 // read_result = *(volatile uint64_t*)virt_addr;
129 bb_error_msg_and_die("bad width");
131 // printf("Written 0x%llX; readback 0x%llX\n",
132 // (unsigned long long)writeval,
133 // (unsigned long long)read_result);
136 if (ENABLE_FEATURE_CLEAN_UP
) {
137 if (munmap(map_base
, mapped_size
) == -1)
138 bb_perror_msg_and_die("munmap");