Files
BPI-M2C/source_sync_rls_25c/source/devtools/lookat/lookat.c
T
2026-09-22 09:38:26 +08:00

305 lines
7.8 KiB
C

/*
* Copyright (C) 2018 Unisoc Company
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdio.h>
#include <sched.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <linux/kernel.h>
#include <linux/magic.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <sys/vfs.h>
#include <sys/mman.h>
/* #define DEBUG */
#ifdef DEBUG
#define DEBUGSEE fprintf
#else
#define DEBUGSEE(...)
#endif
/* option flags */
#define LOOKAT_F_GET (1 << 0)
#define LOOKAT_F_GET_MUL (1 << 1)
#define LOOKAT_F_SET (1 << 2)
#define LOOKAT_F_GET_V (1 << 3)
#define LOOKAT_F_GET_MUL_V (1 << 4)
#define LOOKAT_F_SET_V (1 << 5)
#define LOOKAT_MEM (1 << 6)
static int debugfs_found = 0;
char debugfs_mountpoint[4096 + 1] = "/sys/kernel/debug";
static int debugfs_premounted;
#define SIZE_BUF 24
static const char *debugfs_known_mountpoints[] = {
"/sys/kernel/debug/", "/debug/", "/d/", 0,
};
/* verify that a mountpoint is actually a debugfs instance */
static int debugfs_valid_mountpoint(const char *debugfs) {
struct statfs sta_fs;
if (statfs(debugfs, &sta_fs) < 0)
return -2;
else if (sta_fs.f_type != (long)DEBUGFS_MAGIC)
return -2;
return 0;
}
/* search the path to the mounted debugfs */
static const char *debugfs_find_mountpoint(void) {
const char **mnt_ptr;
char type[100];
FILE *fp;
if (debugfs_found) return (const char *)debugfs_mountpoint;
mnt_ptr = debugfs_known_mountpoints;
while (*mnt_ptr) {
if (debugfs_valid_mountpoint(*mnt_ptr) == 0) {
debugfs_found = 1;
strcpy(debugfs_mountpoint, *mnt_ptr);
return debugfs_mountpoint;
}
mnt_ptr++;
}
/* give up and parse /proc/mounts */
fp = fopen("/proc/mounts", "r");
if (fp == NULL) return NULL;
while (fscanf(fp, "%*s %4096s %99s %*s %*d %*d\n", debugfs_mountpoint,
type) == 2) {
if (strcmp(type, "debugfs") == 0) break;
}
fclose(fp);
if (strcmp(type, "debugfs") != 0) return NULL;
debugfs_found = 1;
return debugfs_mountpoint;
}
/* mount the debugfs somewhere if it's not mounted */
static char *debugfs_mount(const char *mountpoint) {
struct statfs st_fs;
/* see if it's already mounted */
if (debugfs_find_mountpoint()) {
debugfs_premounted = 1;
goto out;
}
/* if not mounted and no argument */
if (mountpoint == NULL) {
/* see if environment variable set */
/* if no environment variable, use default */
mountpoint = "/sys/kernel/debug/";
}
if (statfs("/debug_12345", &st_fs) < 0) {
if (mkdir("/debug_12345/", 0644) < 0) return NULL;
}
if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0) return NULL;
/* save the mountpoint */
debugfs_found = 1;
strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
out:
return debugfs_mountpoint;
}
static int find_create_debugfs(char **p) {
char *_p = 0;
char *debugfs_dir = debugfs_mount("/debug_12345/");
if (!debugfs_dir) return -1;
_p = debugfs_dir;
while (*_p) _p++;
if (*(_p - 1) != '/') {
*(_p) = '/';
*(_p + 1) = 0;
}
DEBUGSEE("debugfs_dir = %s\n", debugfs_dir);
*p = debugfs_dir;
return 0;
}
int sub_main(int flags, unsigned long addr, unsigned long value, int nword) {
int fd1, fd2;
char *dir = 0;
char strPath1[256] = {0};
char strPath2[256] = {0};
char c[12 + 12] = {0};
int n = 0;
ssize_t cnt = 0;
if (find_create_debugfs(&dir)) return 0;
sprintf(strPath1, "%s%s", dir, "lookat/addr_rwpv");
sprintf(strPath2, "%s%s", dir, "lookat/data");
if ((fd1 = open(strPath1, O_RDWR | O_SYNC)) < 0) {
perror("open addr_rwpv");
exit(EXIT_FAILURE);
return -1;
}
if ((fd2 = open(strPath2, O_RDWR | O_SYNC)) < 0) {
perror("open data");
exit(EXIT_FAILURE);
return -1;
}
if ((flags & LOOKAT_F_SET) || (flags & LOOKAT_F_SET_V)) {
if (flags & LOOKAT_F_SET)
addr |= 2;
else
addr |= 3;
n = snprintf(c, SIZE_BUF, "0x%lx", addr);
write(fd1, c, n);
n = snprintf(c, SIZE_BUF, "0x%lx", value);
write(fd2, c, n);
} else if ((flags & LOOKAT_F_GET) || (flags & LOOKAT_F_GET_V)) {
if (flags & LOOKAT_F_GET_V) addr |= 1;
n = snprintf(c, SIZE_BUF, "0x%lx", addr);
write(fd1, c, n);
memset(c, 0, SIZE_BUF);
cnt = read(fd2, c, SIZE_BUF);
if (cnt < 0) {
perror("read data");
exit(EXIT_FAILURE);
return -1;
}
fprintf(stdout, "%s\n", c);
} else if ((flags & LOOKAT_F_GET_MUL) || (flags & LOOKAT_F_GET_MUL_V)) {
int i;
/* print a serial of reg in a formated way */
fprintf(stdout,
" ADDRESS | VALUE\n"
"-----------+-----------\n");
for (i = 0; i < nword; ++i) {
if (flags & LOOKAT_F_GET_MUL_V) addr |= 1;
n = snprintf(c, SIZE_BUF, "0x%lx", addr);
write(fd1, c, n);
memset(c, 0, SIZE_BUF);
cnt = read(fd2, c,
SIZE_BUF); /*It is simple file system don't support seek method
just open again it is quickly.*/
if (cnt < 0) {
perror("read data");
exit(EXIT_FAILURE);
return -1;
}
close(fd2);
if ((fd2 = open(strPath2, O_RDWR | O_SYNC)) < 0) {
fprintf(stderr, "open %s error\n", strPath2);
goto Exit; /*sad*/
}
fprintf(stdout, "0x%lx | %s\n", addr & ~0x3, c);
if (flags & LOOKAT_MEM)
addr += sizeof(unsigned long);
else
addr += 4;
}
}
close(fd2);
Exit:
close(fd1);
return 0;
}
void usage1(void) {
fprintf(stderr,
"\n"
"Usage: lookat [-l nword] [-s value] [-h] addr_in_hex\n"
"get/set the value of IO reg at addr_in_hex\n"
" -l nword print values of nword continous regs start from \n"
" addr_in_hex in a formated way\n"
" -s value set a reg at addr_in_hex to value\n"
" -h print this message\n\n"
" NOTE:\n"
" * the addr_in_hex should be 4-byte aligned in hex form\n"
" * Default is physical address, Using Virtual address If the \n"
" * parameters are capital letter: Only the [-L],[-S],(Read/Write) \n"
" * will use virtual address\n");
}
int main(int argc, char **argv) {
int fd, opt;
int flags = 0; /* option indicator */
unsigned long paddr, pbase, offset;
unsigned long value = 0, nword = 0;
char *vbase;
char *op = "s:l:h:m";
void (*usage)(void);
usage = usage1;
while ((opt = getopt(argc, argv, op)) != -1) {
switch (opt) {
case 's':
flags |= LOOKAT_F_SET;
value = strtoul(optarg, NULL, 16);
fprintf(stdout, "[I] value = 0x%lx\n", value);
break;
case 'l':
flags |= LOOKAT_F_GET_MUL;
nword = strtoul(optarg, NULL, 10);
fprintf(stdout, "[I] nword = 0x%ld\n", nword);
if (nword <= 0) nword = 1;
break;
case 'm':
flags |= LOOKAT_MEM;
break;
case 'h':
usage();
exit(0);
default:
usage();
exit(EXIT_FAILURE);
}
}
if (optind == 1) flags |= LOOKAT_F_GET;
if (optind >= argc) {
fprintf(stderr, "Expected argument after options\n");
exit(EXIT_FAILURE);
}
paddr = strtoul(argv[optind], NULL, 16);
DEBUGSEE(stdout, "[I] paddr = 0x%lx\n", paddr);
if (paddr & 0x3) {
fprintf(stderr, "address should be 4-byte aligned\n");
exit(EXIT_FAILURE);
}
sub_main(flags, paddr, value, nword);
return 0;
}