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