diff --git a/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/bug.h b/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/bug.h index b3e451e8cd..2934178ea1 100644 --- a/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/bug.h +++ b/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/bug.h @@ -3,9 +3,12 @@ #include #include +#include + +#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 diff --git a/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/errno.h b/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/errno.h index 43ef29d04e..0152c591e8 100644 --- a/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/errno.h +++ b/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/errno.h @@ -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) diff --git a/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/slab.h b/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/slab.h index b4a0dabe31..ea56d234a1 100644 --- a/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/slab.h +++ b/local/recipes/drivers/linux-kpi/source/src/c_headers/linux/slab.h @@ -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) \ diff --git a/local/recipes/drivers/linux-kpi/source/src/rust_impl/memory.rs b/local/recipes/drivers/linux-kpi/source/src/rust_impl/memory.rs index 304dcaf356..4e4cee3502 100644 --- a/local/recipes/drivers/linux-kpi/source/src/rust_impl/memory.rs +++ b/local/recipes/drivers/linux-kpi/source/src/rust_impl/memory.rs @@ -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); + } } diff --git a/local/recipes/gpu/amdgpu/source/redox_glue.h b/local/recipes/gpu/amdgpu/source/redox_glue.h index 9f4398bfac..e21a91498f 100644 --- a/local/recipes/gpu/amdgpu/source/redox_glue.h +++ b/local/recipes/gpu/amdgpu/source/redox_glue.h @@ -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 diff --git a/local/recipes/gpu/amdgpu/source/redox_stubs.c b/local/recipes/gpu/amdgpu/source/redox_stubs.c index 9d04a8c55c..b5c4919c9d 100644 --- a/local/recipes/gpu/amdgpu/source/redox_stubs.c +++ b/local/recipes/gpu/amdgpu/source/redox_stubs.c @@ -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); diff --git a/local/recipes/system/firmware-loader/source/Cargo.toml b/local/recipes/system/firmware-loader/source/Cargo.toml index 27711bdc00..e6ab208453 100644 --- a/local/recipes/system/firmware-loader/source/Cargo.toml +++ b/local/recipes/system/firmware-loader/source/Cargo.toml @@ -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" } diff --git a/local/recipes/system/firmware-loader/source/src/blob.rs b/local/recipes/system/firmware-loader/source/src/blob.rs index 37eb53e0a1..714062fcf6 100644 --- a/local/recipes/system/firmware-loader/source/src/blob.rs +++ b/local/recipes/system/firmware-loader/source/src/blob.rs @@ -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, } } diff --git a/local/sources/base b/local/sources/base index 2ade335e3c..e758e68eb3 160000 --- a/local/sources/base +++ b/local/sources/base @@ -1 +1 @@ -Subproject commit 2ade335e3c7433cf5eadd25dc17ea882c51b2a06 +Subproject commit e758e68eb3a22012ca55e1ea97043729f36d8efc diff --git a/local/sources/relibc b/local/sources/relibc index 684ec4a1f5..54ed272d75 160000 --- a/local/sources/relibc +++ b/local/sources/relibc @@ -1 +1 @@ -Subproject commit 684ec4a1f55fdb59c5b0135c0e7dbf0b9112db24 +Subproject commit 54ed272d75ed9652b3dfc2c676c297e374932669