⬢ DragonFlyBSD Kernel Audit
DF-4711 / eqshim.h
← back to finding ↓ download raw
/*
 * eqshim.h — minimal userland shim so the REAL sys/dev/sound/pcm/feeder_eq.c
 * compiles verbatim (unmodified) outside the kernel, exactly like the
 * file's own userland FEEDEQ_ERR_CLIP path anticipates.
 *
 * Values copied faithfully from:
 *   sys/dev/sound/pcm/pcm.h        (intpcm typedefs, _PCM_* LE accessors)
 *   sys/dev/sound/pcm/matrix.h     (SND_CHN_MIN/MAX, SND_MULTICHANNEL)
 *   sys/dev/sound/pcm/sound.h      (AFMT_* encoding macros)
 *   sys/sys/soundcard.h            (AFMT_S16_LE .. values)
 *   sys/dev/sound/pcm/feeder.h     (feeder enums, pcm_feederdesc)
 */
#ifndef EQSHIM_H
#define EQSHIM_H

#include <sys/types.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <limits.h>
#include <errno.h>

typedef int32_t  intpcm_t;
typedef int64_t  intpcm64_t;

#define PCM_S32_MAX	 2147483647
#define PCM_S32_MIN	 (-2147483647 - 1)
#define PCM_16_BPS	2
#define PCM_32_BPS	4

#define SND_CHN_MIN	1
#define SND_CHN_MAX	8			/* matrix.h w/ SND_MULTICHANNEL */

/* ---- AFMT_* (sound.h + sys/soundcard.h) ---- */
#define AFMT_S16_LE	0x00000010
#define AFMT_S32_LE	0x00001000
#define AFMT_ENCODING_MASK	0xf00fffff
#define AFMT_CHANNEL_MASK	0x01f00000
#define AFMT_CHANNEL_SHIFT	20
#define AFMT_ENCODING(v)	((v) & AFMT_ENCODING_MASK)
#define AFMT_CHANNEL(v)		(((v) & AFMT_CHANNEL_MASK) >> AFMT_CHANNEL_SHIFT)
#define AFMT_BIT(v)		(((v) & 0x0000f000) ? 32 :		\
				 (((v) & 0x000f0000) ? 24 :	\
				 (((v) & 0x000000f0) ? 16 : 8)))
#define AFMT_BPS(v)		(AFMT_BIT(v) >> 3)
#define SND_FORMAT(f, c, e)	(AFMT_ENCODING(f) |			\
				 (((c) << AFMT_CHANNEL_SHIFT) &		\
				 AFMT_CHANNEL_MASK))

/* ---- faithful little-endian accessors (pcm.h:110-124 semantics) ---- */
#define INTPCM_T(v)	((intpcm_t)(v))
#define _PCM_READ_S16_LE(b8)		INTPCM_T((int16_t)(((b8)[1] << 8) | (b8)[0]) * 0 + \
					({ int16_t _x; memcpy(&_x, (b8), 2); _x; }))
#define _PCM_WRITE_S16_LE(b8, val)	do {				\
	int16_t _v = (int16_t)(val);					\
	memcpy((b8), &_v, 2);						\
} while (0)
#define _PCM_READ_S32_LE(b8)		INTPCM_T({ int32_t _x; memcpy(&_x, (b8), 4); _x; })
#define _PCM_WRITE_S32_LE(b8, val)	do {				\
	int32_t _v = (int32_t)(val);					\
	memcpy((b8), &_v, 4);						\
} while (0)

/* ---- kernel bits ---- */
#define ksscanf	sscanf
#define ksnprintf snprintf
#define bzero(p, n)	memset((p), 0, (n))
#define min(a, b)	(((a) < (b)) ? (a) : (b))
#define abs(x)		((x) < 0 ? -(x) : (x))
#define rounddown(x, y)	((((x) / (y)) * (y)))

#ifndef M_DEVBUF
#define M_DEVBUF	1
#endif
#define M_WAITOK	0
#define M_ZERO		0

/*
 * Canary allocator: DFly base gcc has no ASan runtime, so detect OOB on the
 * heap-allocated feed_eq_info with front/rear guards + metadata checksums
 * verified by the harness after every feed.
 */
#define EQ_GUARD_FRONT	32
#define EQ_GUARD_REAR	64
extern int eqshim_canary_hit;
extern const char *eqshim_canary_where;

static inline void *
kmalloc(size_t sz, int m, int fl)
{
	unsigned char *base;
	size_t i;

	(void)m; (void)fl;
	base = malloc(sz + EQ_GUARD_FRONT + EQ_GUARD_REAR);
	if (base == NULL)
		return (NULL);
	if (fl & M_ZERO)
		memset(base + EQ_GUARD_FRONT, 0, sz);
	for (i = 0; i < EQ_GUARD_FRONT; i++)
		base[i] = (unsigned char)0xCB;
	for (i = 0; i < EQ_GUARD_REAR; i++)
		base[sz + EQ_GUARD_FRONT + i] = (unsigned char)0xCA;
	return (base + EQ_GUARD_FRONT);
}

static inline void
kfree_canary_check(void *p, size_t sz)
{
	unsigned char *base = (unsigned char *)p - EQ_GUARD_FRONT;
	size_t i;

	if (p == NULL)
		return;
	for (i = 0; i < EQ_GUARD_FRONT; i++)
		if (base[i] != (unsigned char)0xCB) {
			eqshim_canary_hit++;
			eqshim_canary_where = "front guard";
			return;
		}
	for (i = 0; i < EQ_GUARD_REAR; i++)
		if (base[sz + EQ_GUARD_FRONT + i] != (unsigned char)0xCA) {
			eqshim_canary_hit++;
			eqshim_canary_where = "rear guard";
			return;
		}
}

static inline void
kfree(void *p, int m)
{
	(void)m;
	if (p != NULL)
		free((unsigned char *)p - EQ_GUARD_FRONT);
}

static inline size_t
strlcat_shim(char *dst, const char *src, size_t sz)
{
	size_t dl = strlen(dst), sl = strlen(src);
	if (dl < sz - 1) {
		size_t n = sz - dl - 1;
		if (n > sl)
			n = sl;
		memcpy(dst + dl, src, n);
		dst[dl + n] = '\0';
	}
	return (dl + sl);
}
#define strlcat(d, s, n)	strlcat_shim((d), (s), (n))

/* ---- feeder infrastructure (feeder.h) ---- */
enum {
	FEEDER_ROOT, FEEDER_FORMAT, FEEDER_MIXER, FEEDER_RATE, FEEDER_EQ,
	FEEDER_VOLUME, FEEDER_MATRIX, FEEDER_LAST,
};

enum {
	FEEDEQ_CHANNELS, FEEDEQ_RATE, FEEDEQ_TREBLE, FEEDEQ_BASS,
	FEEDEQ_PREAMP, FEEDEQ_STATE, FEEDEQ_DISABLE, FEEDEQ_ENABLE,
	FEEDEQ_BYPASS, FEEDEQ_UNKNOWN
};

struct pcm_feederdesc {
	u_int32_t type;
	u_int32_t in, out;
	u_int32_t flags;
	int idx;
};

struct feeder_class {
	const char		*name;
	void			*methods;
	int			size;
	struct pcm_feederdesc	*desc;
	void			*data;
};

typedef struct kobj_method { int dummy; } kobj_method_t;
#define KOBJMETHOD(m, f)	{ 0 }
#define KOBJMETHOD_END		{ 0 }
#define FEEDER_DECLARE(feeder, pdata)					\
	static struct feeder_class feeder ## _class = {			\
		.name = #feeder,					\
		.methods = NULL,					\
		.size = 0,						\
		.desc = NULL,						\
		.data = pdata,						\
	}

/* real generated fast-division macros — exact kernel arithmetic */
#define SND_USE_FXDIV
#include "snd_fxdiv_gen.h"

/* FEEDER_SET dispatches to the feeder's set method (feed_eq_set) */
struct pcm_channel;		/* opaque */

struct pcm_feeder {
	struct feeder_class	*class;
	struct pcm_feederdesc	*desc;
	void			*data;
	struct pcm_feeder	*source, *parent;
};

extern int eqshim_set(struct pcm_feeder *, int, int);
#define FEEDER_SET(f, w, v)	eqshim_set((f), (w), (v))

/* FEEDER_FEED dispatches to the harness source generator */
extern uint32_t eqshim_source_feed(struct pcm_feeder *, struct pcm_channel *,
    uint8_t *, uint32_t, void *);
#define FEEDER_FEED(f, c, b, cnt, src)	eqshim_source_feed((f), (c), (b), (cnt), (src))

/* device_printf / SND_DECLARE_FILE not reachable outside _KERNEL in this file */

#endif /* EQSHIM_H */