⬢ DragonFlyBSD Kernel Audit
DF-2318 / rig2_shims.h
← back to finding ↓ download raw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
/*
 * rig2_shims.h -- KERNEL-ENVIRONMENT EMULATION for the verbatim pccard.c
 * lifecycle rig (DF-2318 / DF-5355 / DF-5356).
 *
 *   *** NOT VERBATIM *** -- everything the machine-extracted production code
 *   (pccard_core.inc from sys/bus/pccard/pccard.c,
 *    pccard_cis_core.inc from sys/bus/pccard/pccard_cis.c,
 *    subrbus_rl.inc from sys/kern/subr_bus.c)
 *   needs from the kernel environment, emulated in userland:
 *
 *   - device_t is a fake device object; the device method layer
 *     (device_add_child / device_probe_and_attach / device_get_state ...)
 *     mirrors the production subr_bus.c semantics that matter here:
 *       device_doattach(): attach ok -> devadded(dev) -> bus_child_pnpinfo_str
 *                          (subr_bus.c:2107-2114, :633-645)
 *       probe/attach fail -> devnomatch(dev) -> bus_child_pnpinfo_str
 *                          (subr_bus.c:1984/2039 -> :673)
 *   - bus_alloc_resource() implements a bridge window model:
 *       SYS_RES_IOPORT   window [0x110,0x2FF]; fixed ranges granted iff they
 *                        fit; "anywhere" (start==0) granted at the cursor.
 *                        This is the policy a real pcic/cbb bridge enforces
 *                        (its PCI I/O window is finite; fixed host ranges
 *                        outside it cannot be decoded).
 *       SYS_RES_MEMORY size 4096 -> the CIS attribute/common window
 *                        (swapped by CARD_SET_RES_FLAGS, as in DF-2319).
 *       SYS_RES_MEMORY size 1024 RF_ACTIVE -> the CCR mapping window.
 *   - kmalloc/kfree are canary-banded and ledgered (leak accounting).
 *   - panic() prints "RIG KERNEL PANIC: <msg>" and exits 42 -- the userland
 *     analogue of the kernel's panic (which halts the system).
 */
#ifndef RIG2_SHIMS_H
#define RIG2_SHIMS_H

#include <sys/types.h>
#include <sys/queue.h>	/* byte-identical to kernel sys/sys/queue.h (hash-checked) */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>

/* ---------------- kernel types ---------------- */
typedef void driver_intr_t_(void);
#define	driver_intr_t	driver_intr_t_

/* resource types (sys/sys/bus_resource.h:41-44, production values) */
#define	SYS_RES_IRQ	1
#define	SYS_RES_DRQ	2
#define	SYS_RES_MEMORY	3
#define	SYS_RES_IOPORT	4

#define	RF_ACTIVE	0x01
#define	RF_SHAREABLE	0x80
#define	rman_make_alignment_flags(x)	0

/* device states (sys/sys/bus.h:76-81) */
enum rig_devstate { DS_NOTPRESENT, DS_ALIVE, DS_ATTACHING, DS_ATTACHED, DS_BUSY };

/* ---------------- debug knobs (owned here; verbatim code externs them) - */
int pccard_debug = 0;
int pccard_cis_debug = 0;
int bootverbose = 0;

#define	kprintf	printf
#define	ksnprintf	snprintf
#define	ksprintf	sprintf
#define	device_printf(d, ...)	printf("pccard0: " __VA_ARGS__)
#ifndef	howmany
#define	howmany(x, y)	(((x)+((y)-1))/(y))
#endif
#define	bzero(p, n)	memset((p), 0, (n))

static void
rig_panic(const char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	printf("RIG KERNEL PANIC: ");
	vprintf(fmt, ap);
	printf("\n");
	va_end(ap);
	fflush(stdout);
	_exit(42);	/* the kernel would halt here */
}
#define	panic	rig_panic

/* ---------------- allocation ledger ---------------- */
#define	RIG_MAX_BLOCKS	65536
#define	RIG_CANARY	0xC3
#define	M_DEVBUF	0
#define	M_BUS		1
#define	M_NOWAIT	1
#define	M_WAITOK	2
#define	M_INTWAIT	2
#define	M_ZERO		4

struct rig_block {
	void       *p;
	size_t      size;
	int         live;
	const char *site;
};
static struct rig_block rig_blocks[RIG_MAX_BLOCKS];
static int    rig_nblocks;

static void *
rig_kmalloc(size_t sz, int flags, const char *site)
{
	unsigned char *p, *q;
	size_t i;

	if (rig_nblocks >= RIG_MAX_BLOCKS)
		return NULL;
	p = malloc(sz + 16);
	if (p == NULL)
		return NULL;
	for (i = 0; i < 8; i++) p[i] = RIG_CANARY;
	q = p + 8 + sz;
	for (i = 0; i < 8; i++) q[i] = RIG_CANARY;
	if (flags & M_ZERO)
		memset(p + 8, 0, sz);
	rig_blocks[rig_nblocks].p = p + 8;
	rig_blocks[rig_nblocks].size = sz;
	rig_blocks[rig_nblocks].live = 1;
	rig_blocks[rig_nblocks].site = site;
	rig_nblocks++;
	return p + 8;
}
#define	kmalloc(sz, type, flags)	rig_kmalloc((sz), (flags), __func__)

static void
rig_kfree(void *p, const char *site)
{
	int i;
	unsigned char *raw;
	size_t k, sz;

	if (p == NULL)
		return;
	for (i = rig_nblocks - 1; i >= 0; i--)
		if (rig_blocks[i].p == p)
			break;
	if (i < 0) {
		printf("RIG kfree(%p) of UNREGISTERED block (%s)\n", p, site);
		abort();
	}
	if (!rig_blocks[i].live) {
		printf("RIG DOUBLE FREE of %p (%s)\n", p, site);
		abort();
	}
	sz = rig_blocks[i].size;
	raw = (unsigned char *)p - 8;
	for (k = 0; k < 8; k++)
		if (raw[k] != RIG_CANARY || raw[sz + 8 + k] != RIG_CANARY) {
			printf("RIG HEAP SMASH on block %p (%zu bytes, %s)\n",
			    p, sz, rig_blocks[i].site);
			abort();
		}
	rig_blocks[i].live = 0;
	free(raw);
}
#define	kfree(p, type)	rig_kfree((p), __func__)

/* ---------------- fake device tree ---------------- */
struct rig_device {
	struct rig_device *parent;
	struct rig_device *next;	/* global tracking list */
	void		*ivars;
	int		state;
	int		deleted;
	char		nameunit[32];
	char		desc[96];
};
typedef struct rig_device *device_t;

extern struct rig_device rig_bus_dev;	 /* the pccard bus device (pccard0) */
extern struct rig_device rig_bridge_dev; /* pcic/cbb bridge (parent) */
extern struct rig_device *rig_devices;	 /* every child ever added */
extern int rig_nchildren;

/* probe/attach policy for device_probe_and_attach(): how the driver layer
 * answers for pccard function children */
enum rig_probe_mode {
	PROBE_ATTACH_OK,	/* probe+attach succeed -> devadded path */
	PROBE_FAIL,		/* probe fails -> devnomatch path */
	PROBE_SILENT_FAIL	/* fails but suppress the notify (rig-only) */
};
extern int rig_probe_mode;

static __inline device_t
device_add_child(device_t parent, const char *name, int unit)
{
	device_t d = rig_kmalloc(sizeof(struct rig_device), M_ZERO,
	    "device_add_child");
	device_t *tp = &rig_devices;
	(void)name; (void)unit;
	d->parent = parent;
	d->state = DS_NOTPRESENT;
	snprintf(d->nameunit, sizeof(d->nameunit), "pccardfunc%d",
	    rig_nchildren++);
	while (*tp != NULL)
		tp = &(*tp)->next;
	*tp = d;
	return d;
}
static __inline void	device_set_ivars(device_t d, void *iv) { d->ivars = iv; }
static __inline void *	device_get_ivars(device_t d) { return d->ivars; }
static __inline device_t	device_get_parent(device_t d) { return d->parent; }
static __inline int	device_get_state(device_t d) { return d->state; }
static __inline const char *device_get_nameunit(device_t d) { return d->nameunit; }
static __inline void	device_set_desc_copy(device_t d, const char *s)
	{ snprintf(d->desc, sizeof(d->desc), "%s", s); }
static __inline int	device_get_unit(device_t d) { (void)d; return 0; }

/* device_get_softc: only the pccard bus device has a softc here; the storage
 * is defined in rig2_main.c (type known after the verbatim includes). */
extern void *rig_sc_ptr;
static __inline void *	device_get_softc(device_t d) { (void)d; return rig_sc_ptr; }

int bus_child_pnpinfo_str(device_t child, char *buf, size_t buflen);

/* Emulates production device_probe_and_attach() -> device_doattach()
 * (subr_bus.c:2107-2114): on attach success devadded(dev) calls
 * bus_child_pnpinfo_str(); on probe failure devnomatch(dev) does the same
 * (subr_bus.c:1984/2039 -> :673). */
static __inline int
device_probe_and_attach(device_t d)
{
	char buf[1024];

	if (rig_probe_mode == PROBE_ATTACH_OK) {
		d->state = DS_ATTACHED;
		*buf = '\0';
		bus_child_pnpinfo_str(d, buf, sizeof(buf));	/* devadded() */
		printf("    [devadded] %s pnpinfo=\"%s\"\n",
		    d->nameunit, buf);
		return (0);
	}
	if (rig_probe_mode == PROBE_FAIL) {
		*buf = '\0';
		bus_child_pnpinfo_str(d, buf, sizeof(buf));	/* devnomatch() */
	}
	return (ENXIO);
}
static __inline int	device_detach(device_t d)
	{ d->state = DS_NOTPRESENT; return (0); }
static __inline int	device_delete_child(device_t p, device_t d)
	{ (void)p; d->deleted = 1; d->state = DS_NOTPRESENT; return (0); }

/* forward decl: defined VERBATIM in pccard_core.inc (static) */
static int pccard_child_pnpinfo_str(device_t bus, device_t child,
    char *buf, size_t buflen);

/* BUS_CHILD_PNPINFO_STR method dispatch: the pccard bus is the only bus with
 * children in this rig, so the method resolves to the verbatim pccard
 * implementation (production DEVMETHOD table, pccard.c:1340). */
#define	BUS_CHILD_PNPINFO_STR(p, c, b, l)	pccard_child_pnpinfo_str((p), (c), (b), (l))

/* BUS_READ_IVAR dispatch -> verbatim pccard_read_ivar (pccard.c:1339 table);
 * defined in rig2_main.c after the verbatim code is visible. */
int rig_bus_read_ivar(device_t bus, device_t dev, int which, u_char *result);
#define	BUS_READ_IVAR(p, d, w, r)	rig_bus_read_ivar((p), (d), (w), (u_char *)(r))
#define	BUS_TEARDOWN_INTR(d, c, r, ck)	((void)0)	/* intr_handler stays NULL */

/* CARD interface methods (card_if.h) -> bridge shims */
extern long rig_power_enables, rig_power_disables;
extern long rig_flag_switches;
#define	POWER_ENABLE_SOCKET(p, d)	(rig_power_enables++)
#define	POWER_DISABLE_SOCKET(p, d)	(rig_power_disables++)

/* ---------------- rman / resource emulation ---------------- */
typedef struct resource *bus_space_tag_t;
typedef unsigned char  *bus_space_handle_t;
typedef unsigned long   bus_addr_t;
typedef unsigned long   bus_size_t;

struct resource {
	unsigned char *handle;
	size_t         size;
	unsigned long  start, end;
	device_t       owner;
};

#define	RIG_MAPSIZE	4096	/* PCCARD_CIS_SIZE */
#define	RIG_TOTBUF	65536	/* guard: [4096,65536) canary zone */
#define	RIG_CCRBUF	4096

extern unsigned char rig_attr_img[RIG_TOTBUF];
extern unsigned char rig_com_img[RIG_TOTBUF];
extern unsigned char rig_ccr_img[RIG_CCRBUF];

extern struct resource rig_cis_res;
extern struct resource rig_ccr_res;
extern struct resource rig_irq_res;
extern int  rig_space;		/* 0=attribute 1=common */

/* IOPORT window model (what a finite bridge window grants) */
#define	RIG_IO_WIN_START	0x110
#define	RIG_IO_WIN_END		0x2FF
extern unsigned long rig_io_cursor;
extern long rig_io_grants, rig_io_releases;
extern long rig_ccr_allocs, rig_ccr_releases;

#define	RIG_IO_POOL	64
extern struct resource rig_io_pool[RIG_IO_POOL];

struct resource *rig_bus_alloc_io(unsigned long start, unsigned long end,
    unsigned long count);

static __inline struct resource *
bus_alloc_resource(device_t dev, int type, int *rid, bus_addr_t start,
    bus_addr_t end, bus_size_t size, u_int flags)
{
	struct resource *r;

	(void)dev; (void)rid;
	if (type == SYS_RES_MEMORY && size == RIG_MAPSIZE) {
		/* CIS window (pccard_cis.c:130-131) */
		rig_cis_res.handle = rig_attr_img;
		rig_space = 0;
		return &rig_cis_res;
	}
	if (type == SYS_RES_MEMORY && size == (1 << 10) && (flags & RF_ACTIVE)) {
		/* CCR mapping (pccard.c:629-630) */
		rig_ccr_allocs++;
		rig_ccr_res.owner = dev;
		return &rig_ccr_res;
	}
	if (type == SYS_RES_IOPORT) {
		r = rig_bus_alloc_io(start, end, size);
		if (r != NULL)
			r->owner = dev;
		return r;
	}
	return NULL;
}
static __inline struct resource *
bus_alloc_resource_any(device_t dev, int type, int *rid, u_int flags)
{
	(void)dev; (void)rid; (void)flags;
	if (type == SYS_RES_IRQ)
		return &rig_irq_res;
	return NULL;
}
static __inline int
bus_release_resource(device_t dev, int type, int rid, struct resource *res)
{
	int i;
	(void)dev; (void)type; (void)rid;
	if (res == &rig_ccr_res) {
		rig_ccr_releases++;
		return 0;
	}
	if (res == &rig_cis_res || res == &rig_irq_res)
		return 0;
	for (i = 0; i < RIG_IO_POOL; i++)
		if (res == &rig_io_pool[i] && res->size != 0) {
			res->size = 0;
			rig_io_releases++;
			return 0;
		}
	return 0;
}
#define	BUS_RELEASE_RESOURCE(p, d, t, r, res)	bus_release_resource((d), (t), (r), (res))

static __inline bus_space_tag_t	rman_get_bustag(struct resource *r)
	{ return (bus_space_tag_t)r; }
static __inline bus_space_handle_t	rman_get_bushandle(struct resource *r)
	{ return r->handle; }
static __inline unsigned long	rman_get_start(struct resource *r)
	{ return r->start; }
static __inline unsigned long	rman_get_end(struct resource *r)
	{ return r->end; }
static __inline unsigned long	rman_get_size(struct resource *r)
	{ return r->size; }
static __inline device_t	rman_get_device(struct resource *r)
	{ return r->owner; }
static __inline void	rman_set_device(struct resource *r, device_t d)
	{ r->owner = d; }
static __inline int	rman_get_cpuid(struct resource *r)
	{ (void)r; return 0; }

/* CARD_SET_RES_FLAGS: swap the active CIS image (attr/common).  The CCR
 * window call (pccard.c:636-637) is a no-op for the rig's static window. */
static __inline int
rig_CARD_SET_RES_FLAGS(device_t p, device_t d, int t, int r, int flags)
{
	(void)p; (void)d; (void)t; (void)r;
	rig_flag_switches++;
	rig_space = (flags == 0);		/* 0 == PCCARD_A_MEM_COM */
	rig_cis_res.handle = rig_space ? rig_com_img : rig_attr_img;
	return 0;
}
#define	CARD_SET_RES_FLAGS(p, d, t, r, f) \
	rig_CARD_SET_RES_FLAGS((p), (d), (t), (r), (f))

static __inline int
rig_CARD_SET_MEMORY_OFFSET(device_t p, device_t d, int r, uint32_t off,
    uint32_t *deltap)
{
	(void)p; (void)d; (void)r;
	*deltap = off & (RIG_CCRBUF - 1);
	return 0;
}
#define	CARD_SET_MEMORY_OFFSET(p, d, r, o, dp) \
	rig_CARD_SET_MEMORY_OFFSET((p), (d), (r), (o), (dp))

/* ---------------- bus space ---------------- */
static __inline uint8_t
bus_space_read_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t off)
{
	(void)t;
	if (h == rig_ccr_img) {
		if (off >= RIG_CCRBUF) {
			printf("RIG CCR READ OOB off=%lu\n", (unsigned long)off);
			abort();
		}
		return h[off];
	}
	if (off >= RIG_TOTBUF)
		return 0xFF;		/* wild: master-abort analogue */
	return h[off];
}
static __inline void
bus_space_write_1(bus_space_tag_t t, bus_space_handle_t h, bus_size_t off,
    uint8_t v)
{
	(void)t;
	if (h == rig_ccr_img) {
		if (off >= RIG_CCRBUF) {
			printf("RIG CCR WRITE OOB off=%lu\n", (unsigned long)off);
			abort();
		}
		h[off] = v;
		return;
	}
	printf("RIG UNEXPECTED bus_space_write_1 off=%lu v=%#x (dropped)\n",
	    (unsigned long)off, v);
}

#endif /* RIG2_SHIMS_H */