Created
October 8, 2021 10:25
-
-
Save erique/71f1492f46c46c53636938892a0c593a to your computer and use it in GitHub Desktop.
devmem - tool to inspect and manipulate large blocks of physical memory space
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*-------------------------------------------------------------------- | |
* Replay Firmware | |
* www.fpgaarcade.com | |
* All rights reserved. | |
* | |
* admin@fpgaarcade.com | |
* | |
* This Source Code Form is subject to the terms of the Mozilla Public | |
* License, v. 2.0. If a copy of the MPL was not distributed with this | |
* file, You can obtain one at https://mozilla.org/MPL/2.0/. | |
*-------------------------------------------------------------------- | |
* | |
* Copyright (c) 2021, Erik Hemming | |
* | |
*/ | |
// arm-linux-gnueabihf-gcc -Wall -Werror devmem.c -o devmem | |
// Example usage: | |
// | |
// Write a file to physical memory offset 0x20000000 (== 512M) | |
// $ cat background.raw | ./devmem 0x20000000 | |
// | |
// Inspect memory at offset 0x20000000 | |
// $ ./devmem 0x20000000 | xxd | less | |
// | |
// Read back written data as it's being copied | |
// $ cat background.raw | ./devmem 0x20000000 | xxd | less | |
// | |
// Limit the length of data written data | |
// $ cat background.raw | ./devmem 0x20000000 65536 | |
// | |
// Copy a chunk of memory to a file | |
// $ ./devmem 0x20000000 65536 > memory.bin | |
// | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdbool.h> | |
#include <errno.h> | |
#include <fcntl.h> | |
#include <unistd.h> | |
#include <sys/mman.h> | |
int do_transaction(int fd, off_t offset, char* buffer, size_t length, bool reading, bool writing); | |
int main(int argc, const char** argv) | |
{ | |
const bool reading = !isatty(STDOUT_FILENO); | |
const bool writing = !isatty(STDIN_FILENO); | |
if (argc < 2 || argc > 3 || (!reading && !writing)) { | |
fprintf(stderr, "Usage : [ <stdout> | ] %s { address } [ length ] [ | <stdin> ]\n", argv[0]); | |
return -1; | |
} | |
off_t offset = strtoul(argv[1], 0, 0); | |
size_t length = argc == 3 ? strtoul(argv[2], 0, 0) : (size_t) -1; | |
fprintf(stderr, "%s address = %08zx\n", | |
reading && writing ? "Reading and writing" : | |
reading ? "Reading" : "Writing", | |
(size_t)offset); | |
int fd; | |
if ((fd = open("/dev/mem", O_RDWR | O_SYNC)) == -1) { | |
fprintf(stderr, "Unable to open '/dev/mem'; %s (%i)\n", strerror(errno), errno); | |
return -1; | |
} | |
size_t processed = 0; | |
char buf[64 * 1024]; | |
while (length) { | |
size_t bytes_to_read = length > sizeof(buf) ? sizeof(buf) : length; | |
ssize_t bytes_read = writing ? read(STDIN_FILENO, buf, bytes_to_read) : bytes_to_read; | |
if (bytes_read == 0) { | |
break; | |
} | |
int ret = do_transaction(fd, offset, buf, bytes_read, reading, writing); | |
if (ret) { | |
fprintf(stderr, "Unable to map '/dev/mem'; %s (%i)\n", strerror(errno), errno); | |
break; | |
} | |
offset += bytes_read; | |
processed += bytes_read; | |
length -= bytes_read; | |
ssize_t bytes_written = reading ? write(STDOUT_FILENO, buf, bytes_read) : 0; | |
(void) bytes_written; | |
// fprintf(stderr, "Input = %zi bytes ; Output = %zi bytes\n", bytes_read, bytes_written); | |
} | |
close(fd); | |
fprintf(stderr, "Done; Processed %zi bytes\n", processed); | |
} | |
int do_transaction(int fd, off_t offset, char* buffer, size_t length, bool reading, bool writing) | |
{ | |
const size_t page_size = sysconf(_SC_PAGE_SIZE); | |
while (length) { | |
size_t pos_in_page = offset & (page_size - 1); | |
size_t base_offset = offset - pos_in_page; | |
size_t sz = page_size - pos_in_page; | |
if (sz > length) { | |
sz = length; | |
} | |
// fprintf(stderr, "mmap(%08zx); pos_in_page = %zd ; copy %zd bytes\n", base_offset, pos_in_page, sz); | |
int prot = (reading ? PROT_READ : 0) | (writing ? PROT_WRITE : 0); | |
char* base = (char*) mmap(0, page_size, prot, MAP_SHARED, fd, base_offset); | |
if (base == (void*) -1) { | |
return errno; | |
} | |
if (writing) { | |
memcpy(base + pos_in_page, buffer, sz); | |
} | |
if (reading) { | |
memcpy(buffer, base + pos_in_page, sz); | |
} | |
munmap(base, page_size); | |
offset += sz; | |
buffer += sz; | |
length -= sz; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment