210 lines · c
1// SPDX-License-Identifier: GPL-2.02#define _GNU_SOURCE3#include "main.h"4#include <stdlib.h>5#include <stdio.h>6#include <string.h>7#include <pthread.h>8#include <malloc.h>9#include <assert.h>10#include <errno.h>11#include <limits.h>12 13#define SMP_CACHE_BYTES 6414#define cache_line_size() SMP_CACHE_BYTES15#define ____cacheline_aligned_in_smp __attribute__ ((aligned (SMP_CACHE_BYTES)))16#define unlikely(x) (__builtin_expect(!!(x), 0))17#define likely(x) (__builtin_expect(!!(x), 1))18#define ALIGN(x, a) (((x) + (a) - 1) / (a) * (a))19#define SIZE_MAX (~(size_t)0)20#define KMALLOC_MAX_SIZE SIZE_MAX21 22typedef pthread_spinlock_t spinlock_t;23 24typedef int gfp_t;25#define __GFP_ZERO 0x126 27static void *kmalloc(unsigned size, gfp_t gfp)28{29 void *p = memalign(64, size);30 if (!p)31 return p;32 33 if (gfp & __GFP_ZERO)34 memset(p, 0, size);35 return p;36}37 38static inline void *kzalloc(unsigned size, gfp_t flags)39{40 return kmalloc(size, flags | __GFP_ZERO);41}42 43static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags)44{45 if (size != 0 && n > SIZE_MAX / size)46 return NULL;47 return kmalloc(n * size, flags);48}49 50static inline void *kcalloc(size_t n, size_t size, gfp_t flags)51{52 return kmalloc_array(n, size, flags | __GFP_ZERO);53}54 55static void kfree(void *p)56{57 if (p)58 free(p);59}60 61#define kvmalloc_array kmalloc_array62#define kvfree kfree63 64static void spin_lock_init(spinlock_t *lock)65{66 int r = pthread_spin_init(lock, 0);67 assert(!r);68}69 70static void spin_lock(spinlock_t *lock)71{72 int ret = pthread_spin_lock(lock);73 assert(!ret);74}75 76static void spin_unlock(spinlock_t *lock)77{78 int ret = pthread_spin_unlock(lock);79 assert(!ret);80}81 82static void spin_lock_bh(spinlock_t *lock)83{84 spin_lock(lock);85}86 87static void spin_unlock_bh(spinlock_t *lock)88{89 spin_unlock(lock);90}91 92static void spin_lock_irq(spinlock_t *lock)93{94 spin_lock(lock);95}96 97static void spin_unlock_irq(spinlock_t *lock)98{99 spin_unlock(lock);100}101 102static void spin_lock_irqsave(spinlock_t *lock, unsigned long f)103{104 spin_lock(lock);105}106 107static void spin_unlock_irqrestore(spinlock_t *lock, unsigned long f)108{109 spin_unlock(lock);110}111 112#include "../../../include/linux/ptr_ring.h"113 114static unsigned long long headcnt, tailcnt;115static struct ptr_ring array ____cacheline_aligned_in_smp;116 117/* implemented by ring */118void alloc_ring(void)119{120 int ret = ptr_ring_init(&array, ring_size, 0);121 assert(!ret);122 /* Hacky way to poke at ring internals. Useful for testing though. */123 if (param)124 array.batch = param;125}126 127/* guest side */128int add_inbuf(unsigned len, void *buf, void *datap)129{130 int ret;131 132 ret = __ptr_ring_produce(&array, buf);133 if (ret >= 0) {134 ret = 0;135 headcnt++;136 }137 138 return ret;139}140 141/*142 * ptr_ring API provides no way for producer to find out whether a given143 * buffer was consumed. Our tests merely require that a successful get_buf144 * implies that add_inbuf succeed in the past, and that add_inbuf will succeed,145 * fake it accordingly.146 */147void *get_buf(unsigned *lenp, void **bufp)148{149 void *datap;150 151 if (tailcnt == headcnt || __ptr_ring_full(&array))152 datap = NULL;153 else {154 datap = "Buffer\n";155 ++tailcnt;156 }157 158 return datap;159}160 161bool used_empty()162{163 return (tailcnt == headcnt || __ptr_ring_full(&array));164}165 166void disable_call()167{168 assert(0);169}170 171bool enable_call()172{173 assert(0);174}175 176void kick_available(void)177{178 assert(0);179}180 181/* host side */182void disable_kick()183{184 assert(0);185}186 187bool enable_kick()188{189 assert(0);190}191 192bool avail_empty()193{194 return __ptr_ring_empty(&array);195}196 197bool use_buf(unsigned *lenp, void **bufp)198{199 void *ptr;200 201 ptr = __ptr_ring_consume(&array);202 203 return ptr;204}205 206void call_used(void)207{208 assert(0);209}210