amdgpu/linux-kpi: replace remaining stubs with real implementations

- Implement krealloc in linux-kpi memory.rs with GFP-aware tracker lookup,
  copying, and zeroing of grown regions; add krealloc declaration to slab.h
- Align __GFP_ZERO/__GFP_NOWARN and GFP_* values between linux-kpi/slab.h
  and redox_glue.h; make __GFP_ZERO a meaningful flag bit
- Add missing POSIX/errno base constants (EFBIG, EISDIR, ESPIPE, etc.) to
  linux-kpi linux/errno.h so firmware-size checks and other drivers compile
- Harden linux-kpi bug.h: BUG()/BUG_ON() abort, WARN_ON_ONCE only warns once,
  BUILD_BUG_ON uses _Static_assert
- Harden redox_glue.h: add PCI_COMMAND_* flags, CONFIG_HZ/HZ, jiffies
  conversion macros, once-only WARN_ON_ONCE, _Static_assert BUILD_BUG_ON
- Implement redox_pci_enable_device/redox_pci_set_master with real local state
  and command-bit updates; document pcid-spawner pre-enable
- Remove realloc-only krealloc from redox_stubs.c; it now links from linux-kpi
- Fix wait_for_completion_timeout to interpret timeout as jiffies and convert
  to milliseconds, and update msecs/usecs_to_jiffies to use HZ
- Stage previously completed firmware-loader path deps and constructor fix
- Stage base and relibc submodule pointer updates from prior work
This commit is contained in:
2026-07-10 19:44:39 +03:00
parent 705d15ec1f
commit 7c2ea9b5e3
10 changed files with 237 additions and 29 deletions
@@ -3,9 +3,12 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "compiler.h"
#define BUG() \
do { fprintf(stderr, "BUG: %s:%d\n", __FILE__, __LINE__); } while(0)
do { fprintf(stderr, "BUG: %s:%d\n", __FILE__, __LINE__); abort(); } while(0)
#define BUG_ON(condition) \
do { if (unlikely(condition)) { BUG(); } } while(0)
@@ -25,9 +28,18 @@
__ret; \
})
#define WARN_ON_ONCE(condition) WARN_ON(condition)
#define WARN_ON_ONCE(condition) \
({ \
static bool __warned; \
int __ret = !!(condition) && !__warned; \
if (__ret) { \
__warned = true; \
fprintf(stderr, "WARN_ON_ONCE: %s at %s:%d\n", #condition, __FILE__, __LINE__); \
} \
__ret; \
})
#define BUILD_BUG_ON(condition) \
extern char __build_bug_on[(condition) ? -1 : 1] __attribute__((unused))
_Static_assert(!(condition), "BUILD_BUG_ON failed: " #condition)
#endif
@@ -15,21 +15,36 @@
#define ENOMEM 12
#define EACCES 13
#define EFAULT 14
#define ENOTBLK 15
#define EBUSY 16
#define EEXIST 17
#define EXDEV 18
#define ENODEV 19
#define ENOTDIR 20
#define EISDIR 21
#define EINVAL 22
#define ENFILE 23
#define EMFILE 24
#define ENOTTY 25
#define ETXTBSY 26
#define EFBIG 27
#define ENOSPC 28
#define ESPIPE 29
#define EROFS 30
#define EMLINK 31
#define EPIPE 32
#define EDOM 33
#define ERANGE 34
#define ENOSYS 38
#define ENODATA 61
#define ENOSPC 28
#define ENOTCONN 107
#define ENOTEMPTY 39
#define ELOOP 40
#define EWOULDBLOCK EAGAIN
#define ENOMSG 42
#define EIDRM 43
#define EILSEQ 84
#define ENOTSUP 95
#define ETIMEDOUT 110
#define ENOTCONN 107
#define ETIMEDOUT 110
#define IS_ERR_VALUE(x) unlikely((unsigned long)(void *)(x) >= (unsigned long)-4096)
@@ -11,11 +11,16 @@
#define GFP_NOWAIT 4U
#define GFP_DMA 5U
#define __GFP_NOWARN 0U
#define __GFP_ZERO 0U
#ifndef __GFP_NOWARN
#define __GFP_NOWARN 0x200U
#endif
#ifndef __GFP_ZERO
#define __GFP_ZERO 0x100U
#endif
extern void *kmalloc(size_t size, gfp_t flags);
extern void *kzalloc(size_t size, gfp_t flags);
extern void *krealloc(const void *ptr, size_t new_size, gfp_t flags);
extern void kfree(const void *ptr);
#define kmalloc_array(n, size, flags) \
@@ -206,6 +206,65 @@ pub extern "C" fn kfree(ptr: *const u8) {
unsafe { dealloc(ptr as *mut u8, layout) };
}
#[no_mangle]
/// Resize a previously kmalloc'd buffer.
/// Looks up the original allocation in the internal tracker so the correct
/// number of bytes are copied. If the buffer grows and `__GFP_ZERO` is set,
/// the newly allocated region beyond the old size is zeroed.
pub extern "C" fn krealloc(ptr: *const u8, new_size: usize, flags: u32) -> *mut u8 {
const GFP_ZERO: u32 = 0x100;
if new_size == 0 {
kfree(ptr);
return ptr::null_mut();
}
if ptr.is_null() {
return kmalloc(new_size, flags);
}
let mut_ptr = ptr as *mut u8;
let old_layout = {
let mut dma32_tracker = match DMA32_TRACKER.lock() {
Ok(t) => t,
Err(_) => return ptr::null_mut(),
};
if let Some(layout) = dma32_tracker.remove(&SendU8Ptr(mut_ptr)) {
Some(layout)
} else {
let mut tracker = match ALLOC_TRACKER.lock() {
Ok(t) => t,
Err(_) => return ptr::null_mut(),
};
tracker.remove(&SendU8Ptr(mut_ptr))
}
};
let old_size = old_layout.map(|l| l.size()).unwrap_or(0);
let new_ptr = kmalloc(new_size, flags);
if new_ptr.is_null() {
if let Some(layout) = old_layout {
if let Ok(mut tracker) = ALLOC_TRACKER.lock() {
tracker.insert(SendU8Ptr(mut_ptr), layout);
}
}
return ptr::null_mut();
}
let copy_len = old_size.min(new_size);
if copy_len > 0 {
unsafe { ptr::copy_nonoverlapping(ptr, new_ptr, copy_len) };
}
if new_size > old_size && (flags & GFP_ZERO) != 0 {
unsafe { ptr::write_bytes(new_ptr.add(old_size), 0, new_size - old_size) };
}
if let Some(layout) = old_layout {
unsafe { dealloc(mut_ptr, layout) };
}
new_ptr
}
#[cfg(test)]
mod tests {
use super::*;
@@ -268,4 +327,61 @@ mod tests {
kfree(p1);
kfree(p2);
}
#[test]
fn test_krealloc_null_is_kmalloc() {
let p = krealloc(ptr::null(), 64, GFP_KERNEL);
assert!(!p.is_null());
kfree(p);
}
#[test]
fn test_krealloc_zero_size_frees_and_returns_null() {
let p = kmalloc(64, GFP_KERNEL);
assert!(!p.is_null());
assert!(krealloc(p, 0, GFP_KERNEL).is_null());
}
#[test]
fn test_krealloc_grows_and_keeps_data() {
let p = kmalloc(8, GFP_KERNEL);
assert!(!p.is_null());
unsafe { ptr::write_bytes(p, 0xAB, 8) };
let q = krealloc(p, 64, GFP_KERNEL);
assert!(!q.is_null());
for i in 0..8 {
assert_eq!(unsafe { *q.add(i) }, 0xAB);
}
kfree(q);
}
#[test]
fn test_krealloc_zeroes_grown_region() {
const GFP_ZERO: u32 = 0x100;
let p = kmalloc(8, GFP_KERNEL);
assert!(!p.is_null());
unsafe { ptr::write_bytes(p, 0xCD, 8) };
let q = krealloc(p, 64, GFP_ZERO);
assert!(!q.is_null());
for i in 0..8 {
assert_eq!(unsafe { *q.add(i) }, 0xCD);
}
for i in 8..64 {
assert_eq!(unsafe { *q.add(i) }, 0);
}
kfree(q);
}
#[test]
fn test_krealloc_shrinks() {
let p = kmalloc(64, GFP_KERNEL);
assert!(!p.is_null());
unsafe { ptr::write_bytes(p, 0xEF, 64) };
let q = krealloc(p, 8, GFP_KERNEL);
assert!(!q.is_null());
for i in 0..8 {
assert_eq!(unsafe { *q.add(i) }, 0xEF);
}
kfree(q);
}
}
+38 -3
View File
@@ -60,9 +60,18 @@ typedef unsigned int gfp_t;
#define GFP_KERNEL 0U
#define GFP_ATOMIC 1U
#define GFP_DMA32 2U
#define GFP_NOWAIT 3U
#define GFP_HIGHUSER 3U
#define GFP_NOWAIT 4U
#define GFP_DMA 5U
#define GFP_KERNEL_ACCOUNT 0U
#ifndef __GFP_NOWARN
#define __GFP_NOWARN 0x200U
#endif
#ifndef __GFP_ZERO
#define __GFP_ZERO 0x100U
#endif
extern void *kmalloc(size_t size, unsigned int flags);
extern void *kzalloc(size_t size, unsigned int flags);
extern void kfree(const void *ptr);
@@ -286,6 +295,17 @@ extern bool pci_has_quirk(struct pci_dev *dev, u64 flag);
#define IORESOURCE_MEM_64 0x00040000U
#define IORESOURCE_PREFETCH 0x00001000U
#define PCI_COMMAND_IO 0x0001U
#define PCI_COMMAND_MEMORY 0x0002U
#define PCI_COMMAND_MASTER 0x0004U
#define PCI_COMMAND_SPECIAL 0x0008U
#define PCI_COMMAND_INVALIDATE 0x0010U
#define PCI_COMMAND_VGA_PALETTE 0x0020U
#define PCI_COMMAND_PARITY 0x0040U
#define PCI_COMMAND_SERR 0x0100U
#define PCI_COMMAND_FAST_BACK 0x0200U
#define PCI_COMMAND_INTX_DISABLE 0x0400U
/* ---- Firmware loading — maps to scheme:firmware ---- */
struct firmware {
size_t size;
@@ -413,6 +433,13 @@ extern unsigned long redox_wait_for_completion_timeout(struct completion *c, uns
#define PAGE_MASK (~(PAGE_SIZE - 1))
#define PAGE_ALIGN(x) ALIGN((x), PAGE_SIZE)
/* ---- Time / jiffies ---- */
#define CONFIG_HZ 1000
#define HZ CONFIG_HZ
#define jiffies_to_msecs(j) ((unsigned long)(j) * 1000UL / HZ)
#define jiffies_to_usecs(j) ((unsigned long)(j) * 1000000UL / HZ)
/* ---- msleep, udelay — implemented in redox_stubs.c ---- */
extern void msleep(unsigned int msecs);
extern void udelay(unsigned long usecs);
@@ -542,9 +569,17 @@ static inline int list_empty(const struct list_head *head) {
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define WARN_ON(condition) ({ int __ret = !!(condition); if (__ret) fprintf(stderr, "WARN_ON: %s at %s:%d\n", #condition, __FILE__, __LINE__); __ret; })
#define WARN_ON_ONCE(condition) WARN_ON(condition)
#define WARN_ON_ONCE(condition) ({ \
static bool __warned; \
int __ret = !!(condition) && !__warned; \
if (__ret) { \
__warned = true; \
fprintf(stderr, "WARN_ON_ONCE: %s at %s:%d\n", #condition, __FILE__, __LINE__); \
} \
__ret; \
})
#define BUG_ON(condition) do { if (condition) { fprintf(stderr, "BUG: %s at %s:%d\n", #condition, __FILE__, __LINE__); abort(); } } while (0)
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2 * !!(condition)]))
#define BUILD_BUG_ON(condition) _Static_assert(!(condition), "BUILD_BUG_ON failed: " #condition)
/* ---- Enum constants ---- */
#define DRM_MODE_DPMS_ON 0
+34 -15
View File
@@ -118,12 +118,6 @@ void vfree(const void *addr)
free((void *)addr);
}
void *krealloc(const void *ptr, size_t new_size, unsigned int flags)
{
(void)flags;
return realloc((void *)ptr, new_size);
}
static void redox_track_region(void *addr, size_t size, int fd)
{
struct redox_mapped_region *region = malloc(sizeof(*region));
@@ -330,9 +324,18 @@ void *redox_dma_alloc_coherent(size_t size, dma_addr_t *dma_handle)
void redox_dma_free_coherent(size_t size, void *vaddr, dma_addr_t dma_handle)
{
(void)size;
(void)dma_handle;
free(vaddr);
struct redox_mapped_region *region = redox_untrack_region(vaddr);
if (region) {
munmap(region->addr, region->size);
if (region->fd >= 0) {
close(region->fd);
}
free(region);
} else {
free(vaddr);
}
}
/*
@@ -400,13 +403,28 @@ void redox_pci_dev_put(struct pci_dev *pdev)
if (__sync_sub_and_fetch(&pdev->refcount, 1) == 0) {
redox_pci_release_regions(pdev);
free(pdev);
if (pdev != &g_pci_dev) {
free(pdev);
}
}
}
int redox_pci_enable_device(struct pci_dev *pdev)
{
return pdev ? 0 : -ENODEV;
if (!pdev) {
return -ENODEV;
}
if (pdev->enabled) {
return 0;
}
pdev->command |= (u16)(PCI_COMMAND_MEMORY | PCI_COMMAND_IO | PCI_COMMAND_MASTER);
pdev->enabled = true;
dev_info(&pdev->device_obj, "PCI device enabled (memory + I/O + bus master); "
"hardware command register was pre-configured by pcid-spawner\n");
return 0;
}
void redox_pci_set_master(struct pci_dev *pdev)
@@ -415,7 +433,8 @@ void redox_pci_set_master(struct pci_dev *pdev)
return;
}
pdev->command |= (u16)(1U << 2);
pdev->command |= (u16)PCI_COMMAND_MASTER;
dev_info(&pdev->device_obj, "PCI bus master enabled\n");
}
int redox_pci_request_regions(struct pci_dev *pdev, const char *name)
@@ -696,12 +715,12 @@ void mdelay(unsigned long msecs)
unsigned long msecs_to_jiffies(unsigned int msecs)
{
return (unsigned long)msecs;
return (unsigned long)msecs * HZ / 1000UL;
}
unsigned long usecs_to_jiffies(unsigned int usecs)
{
return (unsigned long)DIV_ROUND_UP(usecs, 1000U);
return DIV_ROUND_UP_ULL((unsigned long long)usecs * HZ, 1000000ULL);
}
struct redox_pm_state {
@@ -1178,7 +1197,7 @@ void redox_flush_scheduled_work(void)
unsigned long redox_wait_for_completion_timeout(struct completion *c, unsigned long timeout)
{
struct timespec abs_time;
unsigned long timeout_ms = timeout;
unsigned long timeout_ms = jiffies_to_msecs(timeout);
clock_gettime(CLOCK_REALTIME, &abs_time);
abs_time.tv_sec += timeout_ms / 1000U;
@@ -1191,7 +1210,7 @@ unsigned long redox_wait_for_completion_timeout(struct completion *c, unsigned l
pthread_mutex_lock(&c->mutex);
if (c->done) {
pthread_mutex_unlock(&c->mutex);
return timeout_ms > 0 ? timeout_ms : 1UL;
return timeout;
}
int rc = pthread_cond_timedwait(&c->cond, &c->mutex, &abs_time);
@@ -10,6 +10,7 @@ redox_scheme = { path = "../../../../../local/sources/redox-scheme", package = "
libredox = { path = "../../../../../local/sources/libredox" }
log = { version = "0.4", features = ["std"] }
thiserror = "2"
toml = "0.8"
[patch.crates-io]
libredox = { path = "../../../../../local/sources/libredox" }
@@ -508,6 +508,11 @@ impl FirmwareRegistry {
cache: Arc::new(Mutex::new(HashMap::new())),
persistent_cache,
fallbacks,
builtins: BuiltinRegistry::new(),
stats: Mutex::new(LoadStats::default()),
max_firmware_bytes: u64::MAX,
max_retries: 3,
retry_backoff_ms: 100,
}
}