blob: 9f3780b0b396b1d2bc58dc5a87e90750bdf85e3e [file] [log] [blame] [edit]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
static int usage() {
fprintf(stdout, "Usage: devmem ADDRESS [WIDTH [VALUE]]\n");
fprintf(stdout, " read from or write to device memory.\n");
fprintf(stdout, "\n");
fprintf(stdout, " ADDRESS -- address of device memory\n");
fprintf(stdout, " WIDTH -- 8, 16, or 32(default). required for write\n");
fprintf(stdout, " VALUE -- value to write. read if none is specified\n");
return -1;
}
int devmem_main(int argc, char *argv[])
{
if(argc < 2 || argc > 4) {
return usage();
}
int is_write = (argc == 4);
unsigned long addr = 0, width = 32, value = 0;
addr = strtoul(argv[1], NULL, 0);
if (argc > 2) {
width = strtoul(argv[2], NULL, 0);
if (argc > 3) {
value = strtoul(argv[3], NULL, 0);
}
}
if (width != 8 && width != 16 && width != 32) {
fprintf(stderr, "width has to be 8, 16 or 32\n");
return usage();
}
if (addr % (width >> 3)) {
fprintf(stderr, "address 0x%lx is not %ldbit-aligned\n", addr, width);
return usage();
}
int fd = open("/dev/mem", is_write ? (O_RDWR | O_SYNC) :
(O_RDONLY | O_SYNC));
if (fd == -1) {
fprintf(stderr, "cannot open /dev/mem, error %s\n", strerror(errno));
return -1;
}
int page_size = getpagesize();
void *base = mmap(NULL, page_size,
is_write ? (PROT_READ | PROT_WRITE) : PROT_READ,
MAP_SHARED, fd, addr & ~(page_size - 1));
if (base == MAP_FAILED) {
fprintf(stderr, "mmap failed, error %s\n", strerror(errno));
close(fd);
return -1;
}
void *virt = (char*)base + (addr & (page_size - 1));
if (is_write) {
switch (width) {
case 8:
*(uint8_t*)virt = (uint8_t)value;
break;
case 16:
*(uint16_t*)virt = (uint16_t)value;
break;
case 32:
*(uint32_t*)virt = (uint32_t)value;
break;
default:
fprintf(stderr, "not reached\n");
break;
}
} else {
switch (width) {
case 8:
fprintf(stdout, "0x%02"PRIX8"\n", *(uint8_t*)virt);
break;
case 16:
fprintf(stdout, "0x%04"PRIX16"\n", *(uint16_t*)virt);
break;
case 32:
fprintf(stdout, "0x%08"PRIX32"\n", *(uint32_t*)virt);
break;
default:
fprintf(stderr, "not reached\n");
break;
}
}
munmap(base, page_size);
close(fd);
return 0;
}