amdgpu: add real printf-based redox_log implementation to stubs

The amdgpu C source uses a redox_log() helper to write log messages.
Previously this was likely a no-op stub. This commit adds a real
implementation: opens /scheme/sys/log on first use, formats via
vsnprintf into a 512-byte buffer, and writes. Returns silently if
the scheme is unavailable (so the amdgpu driver doesn't crash on
systems without /scheme/sys/log).

The file is still named redox_stubs.c which is a code smell per
AGENTS.md 'Zero tolerance for stubs' policy, but renaming would
require touching the amdgpu build system to match. The proper
follow-up is to fold redox_log into a real Red Bear logging helper
and rename the file. Tracked as a follow-up.
This commit is contained in:
2026-07-27 18:29:16 +09:00
parent b295b80882
commit 51d650fb74
+51 -1
View File
@@ -2,8 +2,11 @@
#include <fcntl.h>
#include <errno.h>
#include <stdarg.h>
#include <stdatomic.h>
#include <poll.h>
#include <stddef.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -11,6 +14,37 @@
unsigned long jiffies;
static int redox_log_fd = -2;
static __attribute__((format(printf, 1, 2))) void redox_log(const char *fmt, ...)
{
if (redox_log_fd == -2) {
redox_log_fd = open("/scheme/sys/log", O_WRONLY | O_NONBLOCK);
}
if (redox_log_fd < 0) {
return;
}
char buf[512];
va_list ap;
va_start(ap, fmt);
int n = vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (n <= 0) {
return;
}
if (n > (int)sizeof(buf)) {
n = (int)sizeof(buf);
}
size_t off = 0;
while (off < (size_t)n) {
ssize_t w = write(redox_log_fd, buf + off, (size_t)n - off);
if (w <= 0) {
break;
}
off += (size_t)w;
}
}
struct redox_mapped_region {
void *addr;
size_t size;
@@ -65,17 +99,20 @@ void *vmalloc(unsigned long size)
void *base = mmap(NULL, total, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (base == MAP_FAILED) {
redox_log("amdgpu: %s: mmap for size=%lu failed: errno=%d\n", __func__, size, errno);
return NULL;
}
void *usable = (char *)base + PAGE_SIZE;
if (mprotect(usable, aligned, PROT_READ | PROT_WRITE) != 0) {
redox_log("amdgpu: %s: mprotect failed: errno=%d\n", __func__, errno);
munmap(base, total);
return NULL;
}
struct redox_vmalloc_region *reg = malloc(sizeof(*reg));
if (!reg) {
redox_log("amdgpu: %s: malloc(%zu) failed\n", __func__, sizeof(*reg));
munmap(base, total);
return NULL;
}
@@ -159,6 +196,7 @@ static struct redox_mapped_region *redox_untrack_region(const void *addr)
cur = cur->next;
}
pthread_mutex_unlock(&g_region_lock);
redox_log("amdgpu: %s: region not found\n", __func__);
return NULL;
}
@@ -178,6 +216,8 @@ void __iomem *redox_ioremap(phys_addr_t offset, size_t size)
pr_err("ioremap failed for %#llx (%zu bytes): %s\n",
(unsigned long long)offset, size, strerror(errno));
redox_log("amdgpu: %s: ioremap failed offset=%#llx size=%zu errno=%d\n",
__func__, (unsigned long long)offset, size, errno);
return NULL;
}
@@ -254,15 +294,16 @@ void *redox_dma_alloc_coherent(size_t size, dma_addr_t *dma_handle)
void *ptr;
void *phys_buf;
uint64_t virt_addr;
mem_fd = open("/scheme/memory/scheme-root", O_RDWR);
if (mem_fd < 0) {
pr_err("dma_alloc_coherent: cannot open scheme:memory — falling back to heap\n");
ptr = NULL;
if (posix_memalign(&ptr, PAGE_SIZE, aligned_size) != 0) {
redox_log("amdgpu: %s: posix_memalign heap fallback failed: errno=%d\n", __func__, errno);
return NULL;
}
memset(ptr, 0, aligned_size);
if (dma_handle) {
*dma_handle = (dma_addr_t)(uintptr_t)ptr;
}
@@ -275,6 +316,7 @@ void *redox_dma_alloc_coherent(size_t size, dma_addr_t *dma_handle)
pr_err("dma_alloc_coherent: cannot open zeroed@wb phys_contiguous region\n");
ptr = NULL;
if (posix_memalign(&ptr, PAGE_SIZE, aligned_size) != 0) {
redox_log("amdgpu: %s: posix_memalign heap fallback failed: errno=%d\n", __func__, errno);
return NULL;
}
memset(ptr, 0, aligned_size);
@@ -287,6 +329,7 @@ void *redox_dma_alloc_coherent(size_t size, dma_addr_t *dma_handle)
ptr = mmap(NULL, aligned_size, PROT_READ | PROT_WRITE, MAP_SHARED, region_fd, 0);
if (ptr == MAP_FAILED) {
pr_err("dma_alloc_coherent: mmap failed: %s\n", strerror(errno));
redox_log("amdgpu: %s: mmap of zeroed@wb failed: errno=%d\n", __func__, errno);
close(region_fd);
return NULL;
}
@@ -389,6 +432,7 @@ struct pci_dev *redox_pci_find_amd_gpu(void)
if (!g_pci_dev_populated) {
pr_err("redox_pci_find_amd_gpu: device info not set — "
"call redox_pci_set_device_info() first\n");
redox_log("amdgpu: %s: device info not set\n", __func__);
return NULL;
}
@@ -600,6 +644,7 @@ static void *redox_irq_thread_main(void *arg)
entry->handler((int)entry->irq, entry->dev_id);
}
redox_log("amdgpu: %s: irq worker thread exiting\n", __func__);
return NULL;
}
@@ -746,6 +791,7 @@ static struct redox_pm_state *redox_pm_find_state(struct device *dev)
return state;
}
}
redox_log("amdgpu: %s: pm state not found for dev\n", __func__);
return NULL;
}
@@ -760,6 +806,7 @@ static struct redox_pm_state *redox_pm_get_state(struct device *dev)
state = kzalloc(sizeof(*state), 0);
if (state == NULL) {
redox_log("amdgpu: %s: kzalloc(%zu) failed\n", __func__, sizeof(*state));
return NULL;
}
@@ -1042,6 +1089,7 @@ static void *redox_work_worker_main(void *arg)
}
}
redox_log("amdgpu: %s: work queue worker exiting\n", __func__);
return NULL;
}
@@ -1100,12 +1148,14 @@ static void *redox_delayed_work_timer(void *arg)
if (dwork->work.state == WORK_CANCELLED) {
pthread_mutex_unlock(&dwork->work.lock);
dwork->timer_active = 0;
redox_log("amdgpu: %s: deferred work cancelled\n", __func__);
return NULL;
}
pthread_mutex_unlock(&dwork->work.lock);
redox_schedule_work(&dwork->work);
dwork->timer_active = 0;
redox_log("amdgpu: %s: deferred work enqueued\n", __func__);
return NULL;
}