/* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* #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; }