diff --git a/.gitignore b/.gitignore index 8acabb0..1543317 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ gddr6 +build/ +*.o +*.a diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..52ec6cb --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,17 @@ +# CMakeLists.txt +cmake_minimum_required(VERSION 3.10) + +project(gddr6_project) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -Wall") + +add_subdirectory(lib) +add_subdirectory(app) + +install(TARGETS gddr6 + RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin +) + +install(TARGETS gddr6_lib + ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib +) diff --git a/Makefile b/Makefile deleted file mode 100644 index f7d1f61..0000000 --- a/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -all: - gcc -std=c11 -O3 -Wall -Werror -Wextra -Wshadow -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -Wvla -o gddr6 gddr6.c -lpci -clean: - rm -f gddr6 -install: - cp gddr6 /usr/local/bin/ diff --git a/README.md b/README.md index 79f21db..2ddcc97 100644 --- a/README.md +++ b/README.md @@ -17,10 +17,12 @@ sudo update-grub sudo reboot ``` -## Clone & Run +## Installation (cmake) ``` git clone https://github.com/olealgoritme/gddr6 -cd gddr6 && make && sudo ./gddr6 +cd gddr6 +./build_install.sh +sudo gddr6 ``` ## Supported GPUs diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt new file mode 100644 index 0000000..9af7611 --- /dev/null +++ b/app/CMakeLists.txt @@ -0,0 +1,13 @@ +# ./app/CMakeLists.txt +cmake_minimum_required(VERSION 3.10) + +project(gddr6_app) +set(APP_SOURCES src/app.c) +add_executable(gddr6 ${APP_SOURCES}) + +target_link_libraries(gddr6 PRIVATE gddr6_lib) +target_link_libraries(gddr6 PRIVATE pci) + +set_target_properties(gddr6 PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" +) diff --git a/app/src/app.c b/app/src/app.c new file mode 100644 index 0000000..2292301 --- /dev/null +++ b/app/src/app.c @@ -0,0 +1,35 @@ +// app.c +#include "gddr6.h" +#include +#include +#include + +void register_signal_handlers(void) +{ + struct sigaction sa; + sa.sa_handler = gddr6_cleanup; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + + sigaction(SIGINT, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); +} + +int main(int argc, char **argv) +{ + register_signal_handlers(); + gddr6_init(); + int num_devs = gddr6_detect_compatible_gpus(); + + if (num_devs == 0) + { + printf("No compatible GPU found.\n"); + return 1; + } + + gddr6_memory_map(); + gddr6_monitor_temperatures(); + + return 0; +} diff --git a/build_install.sh b/build_install.sh new file mode 100755 index 0000000..ea1923d --- /dev/null +++ b/build_install.sh @@ -0,0 +1,30 @@ +# build_install.sh + +#!/bin/sh + +echo "Creating build directory..." +mkdir -p build && cd build + +echo "Running cmake..." +cmake .. + +echo "Building..." +cmake --build . --config Release + +echo "" +read -p "Do you want to SUDO CMAKE INSTALL libgddr6.a and gddr6 binary to /usr/local? (y/n) " answer + +case $answer in +[Yy]*) + sudo cmake --install . --prefix /usr/local + echo "Installing..." + ;; +[Nn]*) + echo "Skipping installation." + ;; +*) + echo "Please answer y or n." + ;; +esac + +cd .. diff --git a/gddr6.c b/gddr6.c deleted file mode 100644 index b494365..0000000 --- a/gddr6.c +++ /dev/null @@ -1,203 +0,0 @@ -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PG_SZ sysconf(_SC_PAGE_SIZE) -#define PRINT_ERROR() \ - do { \ - fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \ - __LINE__, __FILE__, errno, strerror(errno)); exit(1); \ - } while(0) - - -// device struct -struct device -{ - uint32_t bar0; - uint8_t bus, dev, func; - uint32_t offset; - uint16_t dev_id; - const char *vram; - const char *arch; - const char *name; -}; - - -// variables -int fd; -void *map_base; -struct device devices[32]; - - -// device table -struct device dev_table[] = -{ - { .offset = 0x0000E2A8, .dev_id = 0x2684, .vram = "GDDR6X", .arch = "AD102", .name = "RTX 4090" }, - { .offset = 0x0000E2A8, .dev_id = 0x2704, .vram = "GDDR6X", .arch = "AD103", .name = "RTX 4080" }, - { .offset = 0x0000E2A8, .dev_id = 0x2782, .vram = "GDDR6X", .arch = "AD104", .name = "RTX 4070 Ti" }, - { .offset = 0x0000E2A8, .dev_id = 0x2786, .vram = "GDDR6X", .arch = "AD104", .name = "RTX 4070" }, - { .offset = 0x0000E2A8, .dev_id = 0x2204, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3090" }, - { .offset = 0x0000E2A8, .dev_id = 0x2208, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3080 Ti" }, - { .offset = 0x0000E2A8, .dev_id = 0x2206, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3080" }, - { .offset = 0x0000E2A8, .dev_id = 0x2216, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3080 LHR" }, - { .offset = 0x0000EE50, .dev_id = 0x2484, .vram = "GDDR6", .arch = "GA104", .name = "RTX 3070" }, - { .offset = 0x0000EE50, .dev_id = 0x2488, .vram = "GDDR6", .arch = "GA104", .name = "RTX 3070 LHR" }, - { .offset = 0x0000E2A8, .dev_id = 0x2531, .vram = "GDDR6", .arch = "GA106", .name = "RTX A2000" }, - { .offset = 0x0000E2A8, .dev_id = 0x2571, .vram = "GDDR6", .arch = "GA106", .name = "RTX A2000" }, - { .offset = 0x0000E2A8, .dev_id = 0x2232, .vram = "GDDR6", .arch = "GA102", .name = "RTX A4500" }, - { .offset = 0x0000E2A8, .dev_id = 0x2231, .vram = "GDDR6", .arch = "GA102", .name = "RTX A5000" }, - { .offset = 0x0000E2A8, .dev_id = 0x26B1, .vram = "GDDR6", .arch = "AD102", .name = "RTX A6000" }, - { .offset = 0x0000E2A8, .dev_id = 0x27b8, .vram = "GDDR6", .arch = "AD104", .name = "L4" }, - { .offset = 0x0000E2A8, .dev_id = 0x26b9, .vram = "GDDR6", .arch = "AD102", .name = "L40S" }, - { .offset = 0x0000E2A8, .dev_id = 0x2236, .vram = "GDDR6", .arch = "GA102", .name = "A10" }, -}; - - -// prototypes -void cleanup(int signal); -void cleanup_sig_handler(void); -int pci_detect_dev(void); - - -// cleanup -void cleanup(int signal) -{ - if (signal == SIGHUP || signal == SIGINT || signal == SIGTERM) - { - if (map_base != (void *) -1) - munmap(map_base, PG_SZ); - if (fd != -1) - close(fd); - exit(0); - } -} - - -// cleanup signal handler -void cleanup_sig_handler(void) -{ - struct sigaction sa; - sa.sa_handler = &cleanup; - sa.sa_flags = 0; - sigfillset(&sa.sa_mask); - - if (sigaction(SIGINT, &sa, NULL) < 0) - perror("Cannot handle SIGINT"); - - if (sigaction(SIGHUP, &sa, NULL) < 0) - perror("Cannot handle SIGHUP"); - - if (sigaction(SIGTERM, &sa, NULL) < 0) - perror("Cannot handle SIGTERM"); -} - - -// pci device detection -int pci_detect_dev(void) -{ - struct pci_access *pacc = NULL; - struct pci_dev *pci_dev = NULL; - int num_devs = 0; - ssize_t dev_table_size = (sizeof(dev_table)/sizeof(struct device)); - - pacc = pci_alloc(); - pci_init(pacc); - pci_scan_bus(pacc); - - for (pci_dev = pacc->devices; pci_dev; pci_dev = pci_dev->next) - { - pci_fill_info(pci_dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); - - for (uint32_t i = 0; i < dev_table_size; i++) - { - if (pci_dev->device_id == dev_table[i].dev_id) - { - devices[num_devs] = dev_table[i]; - devices[num_devs].bar0 = (pci_dev->base_addr[0] & 0xFFFFFFFF); - devices[num_devs].bus = pci_dev->bus; - devices[num_devs].dev = pci_dev->dev; - devices[num_devs].func = pci_dev->func; - num_devs++; - } - } - } - - pci_cleanup(pacc); - return num_devs; -} - - -int main(int argc, char **argv) -{ - (void) argc; - (void) argv; - void *virt_addr; - uint32_t temp; - uint32_t phys_addr; - uint32_t read_result; - uint32_t base_offset; - - int num_devs; - char *MEM = "\x2f\x64\x65\x76\x2f\x6d\x65\x6d"; - - num_devs = pci_detect_dev(); - - if (num_devs == 0) - { - printf("No compatible GPU found\n."); - exit(-1); - } - - for (int i = 0; i < num_devs; i++) { - struct device *device = &devices[i]; - printf("Device: %s %s (%s / 0x%04x) pci=%x:%x:%x\n", device->name, device->vram, - device->arch, device->dev_id, device->bus, device->dev, device->func); - } - - if ((fd = open(MEM, O_RDONLY)) == -1) - { - printf("Can't read memory. If you are root, enable kernel parameter iomem=relaxed\n"); - PRINT_ERROR(); - } - - cleanup_sig_handler(); - - - while (1) - { - printf("\rVRAM Temps: |"); - for (int i = 0; i < num_devs; i++) { - struct device *device = &devices[i]; - - phys_addr = (device->bar0 + device->offset); - base_offset = phys_addr & ~(PG_SZ-1); - map_base = mmap(0, PG_SZ, PROT_READ, MAP_SHARED, fd, base_offset); - - if(map_base == (void *) -1) - { - if (fd != -1) - close(fd); - printf("Can't read memory. If you are root, enable kernel parameter iomem=relaxed\n"); - PRINT_ERROR(); - } - virt_addr = (uint8_t *) map_base + (phys_addr - base_offset); - read_result = *((uint32_t *) virt_addr); - temp = ((read_result & 0x00000fff) / 0x20); - - printf(" %3u°C |", temp); - } - fflush(stdout); - sleep(1); - } - - return 0; -} diff --git a/gddr6_use.gif b/gddr6_use.gif deleted file mode 100644 index 7ef2a86..0000000 Binary files a/gddr6_use.gif and /dev/null differ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..7d8437b --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,13 @@ +# ./lib/CMakeLists.txt +cmake_minimum_required(VERSION 3.10) +project(gddr6_lib) +set(LIB_SOURCES src/gddr6.c) + +# Static library (libgddr6) +add_library(gddr6_lib STATIC ${LIB_SOURCES}) +target_include_directories(gddr6_lib PUBLIC include) + +set_target_properties(gddr6_lib PROPERTIES + OUTPUT_NAME "gddr6" # rename libgddr6_lib.a to libgddr6.a + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" +) diff --git a/lib/include/gddr6.h b/lib/include/gddr6.h new file mode 100644 index 0000000..957d71b --- /dev/null +++ b/lib/include/gddr6.h @@ -0,0 +1,33 @@ +// gddr6.h +#ifndef GDDR6_H +#define GDDR6_H + +#include + +struct device +{ + uint32_t bar0; + uint8_t bus, dev, func; + uint32_t offset; + uint16_t dev_id; + const char *vram; + const char *arch; + const char *name; + void *mapped_addr; + uint32_t phys_addr; + uint32_t base_offset; +}; + +struct gddr6_ctx { + struct device *devices; + int num_devices; + int fd; +}; + +void gddr6_init(void); +void gddr6_memory_map(void); +void gddr6_cleanup(int signal); +void gddr6_monitor_temperatures(void); +int gddr6_detect_compatible_gpus(void); + +#endif // GDDR6_H diff --git a/lib/src/gddr6.c b/lib/src/gddr6.c new file mode 100644 index 0000000..60e31a5 --- /dev/null +++ b/lib/src/gddr6.c @@ -0,0 +1,163 @@ +// gddr6.c +#define _GNU_SOURCE + +#include "gddr6.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PG_SZ sysconf(_SC_PAGE_SIZE) +#define PRINT_ERROR() \ + do { \ + fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \ + __LINE__, __FILE__, errno, strerror(errno)); exit(1); \ + } while(0) + +#define MAX_DEVICES 32 + +struct gddr6_ctx ctx = {0}; +struct device dev_table[] = +{ + { .offset = 0x0000E2A8, .dev_id = 0x2684, .vram = "GDDR6X", .arch = "AD102", .name = "RTX 4090" }, + { .offset = 0x0000E2A8, .dev_id = 0x2704, .vram = "GDDR6X", .arch = "AD103", .name = "RTX 4080" }, + { .offset = 0x0000E2A8, .dev_id = 0x2782, .vram = "GDDR6X", .arch = "AD104", .name = "RTX 4070 Ti" }, + { .offset = 0x0000E2A8, .dev_id = 0x2786, .vram = "GDDR6X", .arch = "AD104", .name = "RTX 4070" }, + { .offset = 0x0000E2A8, .dev_id = 0x2204, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3090" }, + { .offset = 0x0000E2A8, .dev_id = 0x2208, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3080 Ti" }, + { .offset = 0x0000E2A8, .dev_id = 0x2206, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3080" }, + { .offset = 0x0000E2A8, .dev_id = 0x2216, .vram = "GDDR6X", .arch = "GA102", .name = "RTX 3080 LHR" }, + { .offset = 0x0000EE50, .dev_id = 0x2484, .vram = "GDDR6", .arch = "GA104", .name = "RTX 3070" }, + { .offset = 0x0000EE50, .dev_id = 0x2488, .vram = "GDDR6", .arch = "GA104", .name = "RTX 3070 LHR" }, + { .offset = 0x0000E2A8, .dev_id = 0x2531, .vram = "GDDR6", .arch = "GA106", .name = "RTX A2000" }, + { .offset = 0x0000E2A8, .dev_id = 0x2571, .vram = "GDDR6", .arch = "GA106", .name = "RTX A2000" }, + { .offset = 0x0000E2A8, .dev_id = 0x2232, .vram = "GDDR6", .arch = "GA102", .name = "RTX A4500" }, + { .offset = 0x0000E2A8, .dev_id = 0x2231, .vram = "GDDR6", .arch = "GA102", .name = "RTX A5000" }, + { .offset = 0x0000E2A8, .dev_id = 0x26B1, .vram = "GDDR6", .arch = "AD102", .name = "RTX A6000" }, + { .offset = 0x0000E2A8, .dev_id = 0x27b8, .vram = "GDDR6", .arch = "AD104", .name = "L4" }, + { .offset = 0x0000E2A8, .dev_id = 0x26b9, .vram = "GDDR6", .arch = "AD102", .name = "L40S" }, + { .offset = 0x0000E2A8, .dev_id = 0x2236, .vram = "GDDR6", .arch = "GA102", .name = "A10" }, +}; + +void gddr6_init(void) +{ + ctx.fd = open("/dev/mem", O_RDONLY); + if (ctx.fd == -1) { + PRINT_ERROR(); + } +} + +int gddr6_detect_compatible_gpus(void) +{ + ctx.devices = NULL; + ctx.num_devices = 0; + + struct pci_access *pacc = NULL; + struct pci_dev *pci_dev = NULL; + ssize_t dev_table_size = (sizeof(dev_table)/sizeof(struct device)); + + pacc = pci_alloc(); + pci_init(pacc); + pci_scan_bus(pacc); + + for (pci_dev = pacc->devices; pci_dev != NULL; pci_dev = pci_dev->next) + { + pci_fill_info(pci_dev, PCI_FILL_IDENT | PCI_FILL_BASES | PCI_FILL_CLASS); + for (uint32_t i = 0; i < dev_table_size; ++i) + { + if (pci_dev->device_id == dev_table[i].dev_id) + { + struct device *new_devices = realloc(ctx.devices, (ctx.num_devices + 1) * sizeof(struct device)); + if (new_devices == NULL) + { + fprintf(stderr, "Memory allocation failed\n"); + pci_cleanup(pacc); + free(ctx.devices); + ctx.devices = NULL; + return 0; + } + ctx.devices = new_devices; + + ctx.devices[i] = dev_table[i]; + ctx.devices[i].bar0 = (pci_dev->base_addr[0] & 0xffffffff); + ctx.devices[i].bus = pci_dev->bus; + ctx.devices[i].dev = pci_dev->dev; + ctx.devices[i].func = pci_dev->func; + ctx.num_devices++; + } + } + } + + pci_cleanup(pacc); + return ctx.num_devices; +} + +void gddr6_memory_map(void) +{ + for (uint32_t i = 0; i < ctx.num_devices; i++) + { + ctx.devices[i].phys_addr = (ctx.devices[i].bar0 + ctx.devices[i].offset); + ctx.devices[i].base_offset = ctx.devices[i].phys_addr & ~(PG_SZ - 1); + + ctx.devices[i].mapped_addr = mmap(0, PG_SZ, PROT_READ, MAP_SHARED, ctx.fd, ctx.devices[i].base_offset); + if (ctx.devices[i].mapped_addr == MAP_FAILED) + { + ctx.devices[i].mapped_addr = NULL; + fprintf(stderr, "Memory mapping failed for pci=%x:%x:%x\n", ctx.devices[i].bus, ctx.devices[i].dev, ctx.devices[i].func); + } else { + printf("Device: %s %s (%s / 0x%04x) pci=%x:%x:%x\n", ctx.devices[i].name, ctx.devices[i].vram, + ctx.devices[i].arch, ctx.devices[i].dev_id, ctx.devices[i].bus, ctx.devices[i].dev, ctx.devices[i].func); + } + } +} + +void gddr6_monitor_temperatures(void) +{ + while (1) { + printf("\rVRAM Temps: |"); + for (uint32_t i = 0; i < ctx.num_devices; i++) + { + if (ctx.devices[i].mapped_addr == NULL || ctx.devices[i].mapped_addr == MAP_FAILED) + { + continue; + } + + void *virt_addr = (uint8_t *) ctx.devices[i].mapped_addr + (ctx.devices[i].phys_addr - ctx.devices[i].base_offset); + uint32_t read_result = *((uint32_t *)virt_addr); + uint32_t temp = ((read_result & 0x00000fff) / 0x20); + + printf(" %3u°C |", temp); + } + fflush(stdout); + sleep(1); + } +} + +void gddr6_cleanup(int signal) +{ + for (uint32_t i = 0; i < ctx.num_devices; i++) + { + if (ctx.devices[i].mapped_addr != NULL && ctx.devices[i].mapped_addr != MAP_FAILED) + { + munmap(ctx.devices[i].mapped_addr, PG_SZ); + ctx.devices[i].mapped_addr = NULL; + } + } + if (ctx.fd != -1) + { + close(ctx.fd); + ctx.fd = -1; + } + if (ctx.devices) + { + free(ctx.devices); + ctx.devices = NULL; + } + exit(signal); +}