]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ppc/net_filter.c
xnu-344.49.tar.gz
[apple/xnu.git] / osfmk / ppc / net_filter.c
CommitLineData
de355530
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
43866e37 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
de355530 7 *
43866e37
A
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
de355530
A
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
43866e37
A
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
de355530
A
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * @OSF_COPYRIGHT@
27 *
28 */
29
30
31#if NET_FILTER_COMPILER
32
33
34#define USE_EXTRA_REGS 0
35
36#define REG_ZERO 0 /* Register we keep equal to 0. */
37#define REG_DATAADDR 3 /* Address of packet data, and filter return. */
38#define REG_DATALEN 4 /* Length of packet data in two-byte units. */
39#define REG_HDRADDR 5 /* Address of header data. */
40#define REG_RET 3 /* Where to put return value. */
41
42/* Originally we dealt in virtual register numbers which were essentially
43 indexes into this array, and only converted to machine register numbers
44 when emitting instructions. But that meant a lot of conversions, so
45 instead we deal with machine register numbers all along, even though this
46 means wasting slots in the regs[] array. */
47const unsigned char scratchregs[] = {
48 6, 7, 8, 9, 10, 11, 12,
49#if USE_EXTRA_REGS /* Callee-saves regs available if we save them. */
50#define INITIAL_NSCRATCHREGS 8 /* Number of registers above. */
51 #error not yet written
52#endif
53};
54#define NSCRATCHREGS (sizeof scratchregs / sizeof scratchregs[0])
55#define NREGS 32
56#define NO_REG 1 /* This is the stack pointer! Flag value. */
57
58#define MAX_LI 0x7fff /* Max unsigned value in an LI. */
59
60#define BCLR(cond) ((19 << 26) | (cond) | (16 << 1))
61#define BLR() BCLR(COND_ALWAYS)
62#define BC(cond, off) ((16 << 26) | (cond) | ((off) << 2))
63#define COND(BO, BI) (((BO) << (16 + 5)) | ((BI) << 16))
64#define COND_ALWAYS COND(COND_IF_ALWAYS, 0)
65#define COND_EQ COND(COND_IF_TRUE, COND_BIT(0, BIT_EQ))
66#define COND_NE COND(COND_IF_FALSE, COND_BIT(0, BIT_EQ))
67#define COND_LE COND(COND_IF_FALSE, COND_BIT(0, BIT_GT))
68#define COND_GE COND(COND_IF_FALSE, COND_BIT(0, BIT_LT))
69#define COND_BIT(crf, bit) \
70 ((crf) * 4 + (bit))
71#define BIT_EQ 2
72#define BIT_GT 1
73#define BIT_LT 0
74#define COND_IF_FALSE 0x04
75#define COND_IF_TRUE 0x0c
76#define COND_IF_ALWAYS 0x14
77
78/* For arithmetical instructions, a is the dest and b is the source;
79 for logical instructions, a is the source and b is the dest. Ho hum. */
80#define IMMED(opcode, a, b, imm) \
81 (((opcode) << 26) | ((a) << 21) | ((b) << 16) | \
82 ((imm) & 0xffff))
83#define ADDI(dst, src, imm) \
84 IMMED(14, dst, src, imm)
85#define ADDIC(dst, src, imm) \
86 IMMED(12, dst, src, imm)
87#define SUBFIC(dst, src, imm) \
88 IMMED(8, dst, src, imm)
89#define LI(dst, imm) ADDI(dst, 0, (imm))
90#define ANDI(dst, src, imm) \
91 IMMED(28, src, dst, imm)
92#define ORI(dst, src, imm) \
93 IMMED(24, src, dst, imm)
94#define XORI(dst, src, imm) \
95 IMMED(26, src, dst, imm)
96
97#define CMPL(lhs, rhs) ((31 << 26) | ((lhs) << 16) | ((rhs) << 11) | (32 << 1))
98#define CMPLI(lhs, imm) ((10 << 26) | ((lhs) << 16) | ((imm) & 0xffff))
99
100#define INTEGER_OP(opcode, a, b, c) \
101 ((31 << 26) | ((a) << 21) | ((b) << 16) | \
102 ((c) << 11) | ((opcode) << 1))
103#define ARITH_OP(opcode, dst, lhs, rhs) \
104 INTEGER_OP(opcode, dst, lhs, rhs)
105#define ADD(dst, lhs, rhs) \
106 ARITH_OP(OP_ADD, dst, lhs, rhs)
107#define ADDE(dst, lhs, rhs) \
108 ARITH_OP(OP_ADDE, dst, lhs, rhs)
109#define SUBF(dst, lhs, rhs) \
110 ARITH_OP(OP_SUBF, dst, lhs, rhs)
111#define SUBFC(dst, lhs, rhs) \
112 ARITH_OP(OP_SUBFC, dst, lhs, rhs)
113#define SUBFE(dst, lhs, rhs) \
114 ARITH_OP(OP_SUBFE, dst, lhs, rhs)
115#define LOGIC_OP(opcode, dst, lhs, rhs) \
116 INTEGER_OP(opcode, lhs, dst, rhs)
117#define OR(dst, lhs, rhs) \
118 LOGIC_OP(OP_OR, dst, lhs, rhs)
119#define XOR(dst, lhs, rhs) \
120 LOGIC_OP(OP_XOR, dst, lhs, rhs)
121#define OP_ADD 266
122#define OP_ADDE 138
123#define OP_AND 28
124#define OP_OR 444
125#define OP_SRW 536
126#define OP_SUBF 40
127#define OP_SUBFC 8
128#define OP_SUBFE 136
129#define OP_XOR 316
130#define MR(dst, src) OR(dst, src, src)
131
132#define LHZ(dst, base, offset) \
133 ((40 << 26) | ((dst) << 21) | ((base) << 16) | \
134 ((offset) & 0xffff))
135#define LHZX(dst, base, index) \
136 INTEGER_OP(279, dst, base, index)
137#define MFCR(dst) INTEGER_OP(19, dst, 0, 0)
138
139#define RLWINM(dst, src, shiftimm, mbegin, mend) \
140 ((21 << 26) | ((src) << 21) | ((dst) << 16) | \
141 ((shiftimm) << 11) | ((mbegin) << 6) | ((mend) << 1))
142#define RLWNM(dst, src, shiftreg, mbegin, mend) \
143 ((23 << 26) | ((src) << 21) | ((dst) << 16) | \
144 ((shiftreg) << 11) | ((mbegin) << 6) | ((mend) << 1))
145
146/* Every NETF_arg generates at most four instructions (4 for PUSHIND).
147 Every NETF_op generates at most 3 instructions (3 for EQ and NEQ). */
148#define MAX_INSTR_PER_ARG 4
149#define MAX_INSTR_PER_OP 3
150#define MAX_INSTR_PER_ITEM (MAX_INSTR_PER_ARG + MAX_INSTR_PER_OP)
151int junk_filter[MAX_INSTR_PER_ITEM];
152
153enum {NF_LITERAL, NF_HEADER, NF_DATA};
154struct common { /* Keeps track of values we might want to avoid reloading. */
155 char type; /* NF_LITERAL: immediate; NF_HEADER: header word;
156 NF_DATA: data word. */
157 char nuses; /* Number of remaining uses for this value. */
158 unsigned char reg;
159 /* Register this value is currently in, or NO_REG if none. */
160 unsigned short value;
161 /* Immediate value or header or data offset. */
162};
163struct reg { /* Keeps track of the current contents of registers. */
164 unsigned char commoni;
165 /* Index in common[] of the contained value. */
166#define NOT_COMMON_VALUE NET_MAX_FILTER /* When not a common[] value. */
167 unsigned char stacktimes;
168 /* Number of times register appears in stack. */
169};
170struct local { /* Gather local arrays so we could kalloc() if needed. */
171 struct common common[NET_MAX_FILTER]; /* Potentially common values. */
172 struct reg regs[NREGS]; /* Register statuses. */
173 unsigned char commonpos[NET_MAX_FILTER]; /* Index in common[] for the
174 value loaded in each filter
175 command. */
176 unsigned char stackregs[NET_FILTER_STACK_DEPTH];
177 /* Registers making up the
178 stack. */
179#if USE_EXTRA_REGS
180 unsigned char maxreg;
181#endif
182};
183
184int allocate_register(struct local *s, int commoni);
185int compile_preamble(int *instructions, struct local *s);
186
187/* Compile a packet filter into POWERPC machine code. We do everything in
188 the 7 caller-saves registers listed in scratchregs[], except when
189 USE_EXTRA_REGS is defined, in which case we may also allocate callee-
190 saves registers if needed. (Not yet implemented on PPC.)
191
192 Rather than maintaining an explicit stack in memory, we allocate registers
193 dynamically to correspond to stack elements -- we can do this because we
194 know the state of the stack at every point in the filter program. We also
195 attempt to keep around in registers values (immediates, or header or data
196 words) that are used later on, to avoid having to load them again.
197 Since there are only 7 registers being used, we might be forced to reload
198 a value that we could have kept if we had more. We might even be unable
199 to contain the stack in the registers, in which case we return failure and
200 cause the filter to be interpreted by net_do_filter(). But for all current
201 filters I looked at, 7 registers is enough even to avoid reloads. When
202 USE_EXTRA_REGS is defined there are about 28 available registers, which is
203 plenty.
204
205 We depend heavily on NET_MAX_FILTER and NET_FILTER_STACK_DEPTH being
206 small. We keep indexes to arrays sized by them in char-sized fields,
207 originally because we tried allocating these arrays on the stack.
208 Even then we overflowed the small (4K) kernel stack, so we were forced
209 to allocate the arrays dynamically, which is the reason for the existence
210 of `struct local'.
211
212 We also depend on the filter being logically correct, for instance not
213 being longer than NET_MAX_FILTER or underflowing its stack. This is
214 supposed to have been checked by parse_net_filter() before the filter
215 is compiled.
216
217 We are supposed to return 1 (TRUE) if the filter accepts the packet
218 and 0 (FALSE) otherwise. In fact, we may return any non-zero value
219 for true, which is sufficient for our caller and convenient for us.
220
221 There are lots and lots of optimisations that we could do but don't.
222 This is supposedly a *micro*-kernel, after all. Here are some things
223 that could be added without too much headache:
224 - Using the condition register. We go to a lot of trouble to generate
225 integer truth values for EQ etc, but most of the time those values
226 are just ANDed or ORed together or used as arguments to COR etc. So
227 we could compute the comparison values directly into CR bits and
228 operate on them using the CR logical instructions without (most of
229 the time) ever having to generate integer equivalents.
230 - More registers. We could note the last uses of r3, r4, and
231 r5, and convert them to general registers after those uses. But if
232 register shortage turns out to be a problem it is probably best just
233 to define USE_EXTRA_REGS and have done with it.
234 - Minimising range checks. Every time we refer to a word in the data
235 part, we generate code to ensure that it is within bounds. But often
236 the truth of these tests is implied by earlier tests. Instead, at the
237 start of the filter and after every COR or CNAND we could insert
238 a single check when that is necessary. (After CAND and CNOR we don't
239 need to check since if they terminate it will be to return FALSE
240 anyway so all we'd do would be to return it prematurely.)
241 - Remembering immediate values. Instead of generating code as soon as we
242 see a PUSHLIT, we could remember that value and only generate code when
243 it is used. This would enable us to generate certain shorter
244 instructions (like addi) that incorporate the immediate value instead
245 of ever putting it in a register.
246 */
247
248filter_fct_t
249net_filter_alloc(filter_t *filter, unsigned int size, unsigned int *lenp)
250{
251 struct local *s;
252 int len, oldi, i, j, t, ncommon, sp;
253 int type, value, arg, op, reg, reg1, dst, commoni;
254 int returnfalseoffset;
255 int *instructions, *instp, *returnfalse;
256#if USE_EXTRA_REGS
257 int oldmaxreg;
258#endif
259 boolean_t compiling;
260
261#define SCHAR_MAX 127 /* machine/machlimits->h, anyone? */
262 assert(NET_MAX_FILTER <= SCHAR_MAX);
263 assert(NET_FILTER_STACK_DEPTH <= SCHAR_MAX);
264 assert(NREGS <= SCHAR_MAX);
265
266 assert(size < NET_MAX_FILTER);
267
268 s = (struct local *) kalloc(sizeof *s);
269
270#if USE_EXTRA_REGS
271 s->maxreg = INITIAL_NSCRATCHREGS;
272#endif
273 len = 0;
274 compiling = FALSE;
275 returnfalse = junk_filter;
276
277 /* This loop runs at least twice, once with compiling==FALSE to determine
278 the length of the instructions we will compile, and once with
279 compiling==TRUE to compile them. The code generated on the two passes
280 must be the same. In the USE_EXTRA_REGS case, the loop can be re-run
281 an extra time while !compiling, if we decide to use the callee-saves
282 registers. This is because we may be able to generate better code with
283 the help of these registers than before. */
284 while (1) {
285
286 /* Identify values that we can potentially preserve in a register to
287 avoid having to reload them. All immediate values and references to
288 known offsets in the header or data are candidates. The results of
289 this loop are the same on every run, so with a bit of work we
290 could run it just once; but this is not a time-critical
291 application. */
292 ncommon = 0;
293 for (i = 0; i < size; i++) {
294 oldi = i;
295 arg = NETF_ARG(filter[i]);
296 if (arg == NETF_PUSHLIT) {
297 type = NF_LITERAL;
298 value = filter[++i];
299 } else if (arg >= NETF_PUSHSTK) {
300 continue;
301 } else if (arg >= NETF_PUSHHDR) {
302 type = NF_HEADER;
303 value = arg - NETF_PUSHHDR;
304 } else if (arg >= NETF_PUSHWORD) {
305 type = NF_DATA;
306 value = arg - NETF_PUSHWORD;
307 } else {
308 continue;
309 }
310 for (j = 0; j < ncommon; j++) {
311 if (s->common[j].type == type && s->common[j].value == value) {
312 s->common[j].nuses++;
313 break;
314 }
315 }
316 if (j == ncommon) {
317 s->common[j].type = type;
318 s->common[j].value = value;
319 s->common[j].nuses = 1;
320 ncommon++;
321 }
322 s->commonpos[oldi] = j;
323 }
324
325#if USE_EXTRA_REGS
326 oldmaxreg = s->maxreg;
327#endif
328
329 /* Initially, no registers hold common values or are on the stack. */
330 for (i = 0; i < ncommon; i++)
331 s->common[i].reg = NO_REG;
332 for (i = 0; i < NSCRATCHREGS; i++) {
333 s->regs[scratchregs[i]].commoni = NOT_COMMON_VALUE;
334 s->regs[scratchregs[i]].stacktimes = 0;
335 }
336
337 /* Now read through the filter and generate code. */
338 sp = -1; /* sp points to top element */
339 for (i = 0; i < size; i++) {
340 if (!compiling)
341 instp = junk_filter;
342
343 assert(sp >= -1);
344 assert(sp < NET_FILTER_STACK_DEPTH - 1);
345 commoni = s->commonpos[i];
346 arg = NETF_ARG(filter[i]);
347 op = NETF_OP(filter[i]);
348
349 /* Generate code to get the required value into a register and
350 set `reg' to the number of this register. */
351 switch (arg) {
352 case NETF_PUSHLIT:
353 value = filter[++i];
354 reg = s->common[commoni].reg;
355 if (reg == NO_REG) {
356 if ((reg = allocate_register(s, commoni)) == NO_REG)
357 goto fail;
358 assert(value >= 0); /* Comes from unsigned short. */
359 *instp++ = ORI(reg, REG_ZERO, value);
360 }
361 s->common[commoni].nuses--;
362 break;
363 case NETF_NOPUSH:
364 reg = s->stackregs[sp--];
365 s->regs[reg].stacktimes--;
366 break;
367 case NETF_PUSHZERO:
368 reg = REG_ZERO;
369 break;
370 case NETF_PUSHIND:
371 case NETF_PUSHHDRIND:
372 reg1 = s->stackregs[sp--];
373 s->regs[reg1].stacktimes--;
374 if (arg == NETF_PUSHIND)
375 *instp++ = CMPL(reg1, REG_DATALEN);
376 else
377 *instp++ = CMPLI(reg1,
378 NET_HDW_HDR_MAX/sizeof (unsigned short));
379 *instp = BC(COND_GE, returnfalse - instp);
380 instp++;
381 if ((reg = allocate_register(s, -1)) == NO_REG)
382 goto fail;
383 *instp++ = ADD(reg, reg1, reg1);
384 *instp++ = LHZX(reg, (arg == NETF_PUSHIND) ?
385 REG_DATAADDR : REG_HDRADDR, reg);
386 break;
387 default:
388 if (arg >= NETF_PUSHSTK)
389 reg = s->stackregs[sp - (arg - NETF_PUSHSTK)];
390 else if (arg >= NETF_PUSHWORD) {
391 assert(2 * (NETF_PUSHHDR - NETF_PUSHWORD) <= MAX_LI);
392 assert(NETF_PUSHSTK - NETF_PUSHHDR <= MAX_LI);
393 reg = s->common[commoni].reg;
394 if (reg == NO_REG) {
395 if ((reg = allocate_register(s, commoni)) == NO_REG)
396 goto fail;
397 if (arg < NETF_PUSHHDR) {
398 value = arg - NETF_PUSHWORD;
399 *instp++ = CMPLI(REG_DATALEN, value);
400 *instp = BC(COND_LE, returnfalse - instp);
401 instp++;
402 reg1 = REG_DATAADDR;
403 } else {
404 value = arg - NETF_PUSHHDR;
405 reg1 = REG_HDRADDR;
406 }
407 *instp++ = LHZ(reg, reg1, 2 * value);
408 }
409 s->common[commoni].nuses--;
410 }
411 }
412
413 /* Now generate code to do `op' on `reg1' (lhs) and `reg' (rhs). */
414 if (op != NETF_NOP) {
415 reg1 = s->stackregs[sp--];
416 s->regs[reg1].stacktimes--;
417 }
418 switch (op) {
419 case NETF_OP(NETF_CAND):
420 case NETF_OP(NETF_COR):
421 case NETF_OP(NETF_CNAND):
422 case NETF_OP(NETF_CNOR):
423 dst = -1;
424 case NETF_OP(NETF_NOP):
425 break;
426 default:
427 /* Allocate a register to put the result in. */
428 if ((dst = allocate_register(s, -1)) == NO_REG)
429 goto fail;
430 }
431 switch (op) {
432 case NETF_OP(NETF_NOP):
433 dst = reg;
434 break;
435 case NETF_OP(NETF_EQ):
436 case NETF_OP(NETF_NEQ):
437 /* We arrange for the truth value to end up in the carry
438 flag and then put it in the destination register by
439 adding-with-carry zero to itself. To set the carry, we
440 first make a value `x' that is zero if the values are
441 equal; this is either their XOR, or, if we know the
442 rhs is 0, the lhs. Then to set the carry only when
443 x==0 we do `subfic dst,x,0' (subtract x from 0, setting
444 carry as not-borrow, so set only if x==0); to set it when
445 x!=0 we do `addic dst,x,-1' (add -1 to x setting carry,
446 so set unless x==0). We're only interested in the carry
447 from these operations, not dst.
448 We don't test if reg1==REG_ZERO since in practice you
449 write NETF_PUSHLIT|NETF_EQ; the other order is eccentric
450 so you get an extra instruction, tough. */
451 if (reg == REG_ZERO)
452 t = reg1;
453 else {
454 *instp++ = XOR(dst, reg1, reg);
455 t = dst;
456 }
457 *instp++ = (op == NETF_OP(NETF_EQ)) ?
458 SUBFIC(dst, t, 0) : ADDIC(dst, t, -1);
459 *instp++ = ADDE(dst, REG_ZERO, REG_ZERO);
460 break;
461 case NETF_OP(NETF_LT):
462 /* LT and GT take advantage of the fact that all numbers are
463 16-bit quantities, so the sign bit after a subtraction
464 is a reliable indication of the relative magnitudes of
465 the operands. */
466 *instp++ = SUBF(dst, reg, reg1); /* dst = reg1 - reg */
467 *instp++ = RLWINM(dst, dst, 1, 31, 31); /* sign bit */
468 break;
469 case NETF_OP(NETF_GT):
470 *instp++ = SUBF(dst, reg1, reg); /* dst = reg - reg1 */
471 *instp++ = RLWINM(dst, dst, 1, 31, 31); /* sign bit */
472 break;
473 case NETF_OP(NETF_LE):
474 /* LE and GE use the carry (= not-borrow) flag. When doing
475 a - b, there is a borrow if b > a, so carry if b <= a. */
476 *instp++ = SUBFC(dst, reg1, reg); /* dst = reg - reg1 */
477 *instp++ = ADDE(dst, REG_ZERO, REG_ZERO);/* ca if reg1 <= reg */
478 break;
479 case NETF_OP(NETF_GE):
480 *instp++ = SUBFC(dst, reg, reg1); /* dst = reg1 - reg */
481 *instp++ = ADDE(dst, REG_ZERO, REG_ZERO);/* ca if reg <= reg1 */
482 break;
483 case NETF_OP(NETF_AND):
484 j = OP_AND;
485 goto logical;
486 case NETF_OP(NETF_OR):
487 j = OP_OR;
488 goto logical;
489 case NETF_OP(NETF_XOR):
490 j = OP_XOR;
491 goto logical;
492 case NETF_OP(NETF_RSH):
493 j = OP_SRW;
494logical:
495 *instp++ = LOGIC_OP(j, dst, reg1, reg);
496 break;
497 case NETF_OP(NETF_ADD):
498 j = OP_ADD;
499 goto arithmetical;
500 case NETF_OP(NETF_SUB):
501 j = OP_SUBF; /* First reg subtracted from second. */
502arithmetical:
503 *instp++ = ARITH_OP(j, dst, reg, reg1);
504 *instp++ = ANDI(dst, dst, 0xffff);
505 break;
506 case NETF_OP(NETF_LSH):
507 *instp++ = RLWNM(dst, reg1, reg, 16, 31);
508 break;
509 case NETF_OP(NETF_COR):
510 case NETF_OP(NETF_CNAND):
511 *instp++ = CMPL(reg1, reg);
512 *instp++ = BCLR((op == NETF_OP(NETF_COR)) ? COND_EQ : COND_NE);
513 break;
514 case NETF_OP(NETF_CAND):
515 case NETF_OP(NETF_CNOR):
516 *instp++ = CMPL(reg1, reg);
517 *instp = BC((op == NETF_OP(NETF_CAND)) ? COND_NE : COND_EQ,
518 returnfalse - instp);
519 instp++;
520 break;
521 default:
522 printf("op == 0x%x\n", op);
523 panic("net_filter_alloc: bad op");
524 /* Should have been caught by parse_net_filter(). */
525 }
526 /* If the op generated a result, push it on the stack. */
527 if (dst >= 0) {
528 s->stackregs[++sp] = dst;
529 s->regs[dst].stacktimes++;
530 }
531 if (!compiling) {
532 assert(instp - junk_filter <= MAX_INSTR_PER_ITEM);
533 len += instp - junk_filter;
534 }
535 }
536 if (compiling) {
537 /* If the stack contains any values, we are supposed to return 0 or
538 1 according as the top-of-stack is zero or not. Since the only
539 place we are called requires just zero-false/nonzero-true, we
540 simply copy the value into r3. If the stack is empty, we
541 leave the pointer value r3 intact to return TRUE. */
542 if (sp >= 0)
543 *instp++ = MR(REG_RET, s->stackregs[sp]);
544 *instp++ = BLR();
545 /* Branch here to return false. We could avoid adding these
546 instructions if they are not used, but practically every
547 filter does use them (for failure values when trying to
548 access values beyond the header or data length) so it's
549 not worth the effort. */
550 assert(instp == returnfalse);
551 *instp++ = LI(REG_RET, 0);
552 *instp++ = BLR();
553 break;
554 } else {
555 len += 1 + (sp >= 0);
556 /* For the reach-the-end return instruction(s). */
557#if USE_EXTRA_REGS
558 if (s->maxreg > oldmaxreg) {
559 len = 0;
560 continue;
561 }
562#endif
563 len += compile_preamble(NULL, s);
564 returnfalseoffset = len;
565 len += 2; /* For the return-false instructions. */
566 }
567 if ((instructions = (int *) kalloc(len * sizeof (int))) == NULL)
568 return NULL;
569 returnfalse = instructions + returnfalseoffset;
570 instp = instructions;
571 instp += compile_preamble(instp, s);
572 compiling = TRUE;
573 }
574
575 assert(instp - instructions == len);
576 *lenp = len * sizeof (int);
577 {
578 kern_return_t kr;
579 vm_machine_attribute_val_t val = MATTR_VAL_CACHE_SYNC;
580
581 kr = pmap_attribute(kernel_pmap, (vm_offset_t) instructions,
582 len * sizeof (int), MATTR_CACHE, &val);
583 if (kr != KERN_SUCCESS) {
584 printf("net_filter_alloc: pmap_attribute -> 0x%x\n", kr);
585 return NULL;
586 }
587 }
588 kfree((vm_offset_t) s, sizeof *s);
589 return (filter_fct_t) instructions;
590fail:
591 assert(!compiling);
592 kfree((vm_offset_t) s, sizeof *s);
593 printf("net_filter_alloc: failed to compile (filter too complex)\n");
594 printf("-- will work, but more slowly; consider enabling USE_EXTRA_REGS\n");
595 return NULL;
596}
597
598
599/* Allocate a register. Registers that are already being used to make up
600 the virtual stack are ineligible. Among the others, we choose the one
601 whose value has the least number of subsequent uses (ideally, and
602 usually, 0) of the common value it already holds. If commoni is >=
603 0, it is the index in common[] of the value we are going to put in
604 the allocated register, so we can update the various data structures
605 appropriately. */
606int
607allocate_register(struct local *s, int commoni)
608{
609 int i, reg, bestreg, nuses, bestregnuses, maxreg;
610
611 bestreg = NO_REG;
612#if USE_EXTRA_REGS
613 maxreg = s->maxreg;
614#else
615 maxreg = NSCRATCHREGS;
616#endif
617 while (1) {
618 bestregnuses = NOT_COMMON_VALUE;
619 for (i = 0; i < maxreg; i++) {
620 reg = scratchregs[i];
621 if (s->regs[reg].stacktimes == 0) {
622 nuses = (s->regs[reg].commoni == NOT_COMMON_VALUE) ?
623 0 : s->common[s->regs[reg].commoni].nuses;
624 if (nuses < bestregnuses) {
625 bestreg = reg;
626 bestregnuses = nuses;
627 }
628 }
629 }
630 if (bestreg != NO_REG)
631 break;
632#if USE_EXTRA_REGS
633 if (maxreg == NSCRATCHREGS)
634 return NO_REG;
635 s->maxreg = ++maxreg;
636#else
637 return NO_REG;
638#endif
639 }
640 if (bestregnuses > 0)
641 printf("net_filter_alloc: forced to reallocate r%d\n", bestreg);
642 /* With USE_EXTRA_REGS, we could push up the number of registers
643 here to have one extra available for common values, but it's usually
644 not worth the overhead of the extra save-and-restore in the preamble.
645 Anyway, this never happens with typical filters. */
646 if (s->regs[bestreg].commoni != NOT_COMMON_VALUE)
647 s->common[s->regs[bestreg].commoni].reg = NO_REG;
648 if (commoni >= 0) {
649 s->regs[bestreg].commoni = commoni;
650 s->common[commoni].reg = bestreg;
651 } else
652 s->regs[bestreg].commoni = NOT_COMMON_VALUE;
653 return bestreg;
654}
655
656
657#define FIXED_PREAMBLE_INSTRUCTIONS 1
658
659int
660compile_preamble(int *instructions, struct local *s)
661{
662 int *instp;
663 int len = FIXED_PREAMBLE_INSTRUCTIONS;
664#if USE_EXTRA_REGS
665#error this hp code must be ported to the ppc
666 int extra_regs, i, j, t, disp;
667
668 extra_regs = s->maxreg - INITIAL_NSCRATCHREGS;
669 if (extra_regs > 0) {
670 len = extra_regs * 2 + 4;
671 /* stw rp | (n-1) * stw | bl | stw | ldw rp | (n-1) * ldw | bv | ldw */
672 } else
673 return 0;
674#endif
675 if (instructions == NULL)
676 return len;
677 instp = instructions;
678
679 *instp++ = LI(REG_ZERO, 0);
680 assert(instp - instructions == FIXED_PREAMBLE_INSTRUCTIONS);
681
682#if USE_EXTRA_REGS
683#error this hp code must be ported to the ppc
684 /* Generate a wrapper function to save the callee-saves registers
685 before invoking the filter code we have generated. It would be
686 marginally better to have the filter branch directly to the
687 postamble code on return, but the difference is trivial and it
688 is easier to have it always branch to (rp). */
689#define FRAME_SIZE 128 /* This is plenty without being excessive. */
690 *instp++ = STW_NEG(REG_RTN, 20, REG_SP); /* stw rp,-20(sp) */
691 i = INITIAL_NSCRATCHREGS;
692 t = STWM(scratchregs[i], FRAME_SIZE, REG_SP); /* stwm r3,128(sp) */
693 j = FRAME_SIZE;
694 while (++i < s->maxreg) {
695 *instp++ = t;
696 j -= sizeof (int);
697 t = STW_NEG(scratchregs[i], j, REG_SP); /* stw r4,-124(sp) &c */
698 }
699 disp = extra_regs + 2; /* n * ldw | bv | ldw rp */
700 *instp++ = BL(disp, REG_RTN); /* bl filter,rp */
701 *instp++ = t; /* stw in delay slot */
702 *instp++ = LDW_NEG(FRAME_SIZE + 20, REG_SP, REG_RTN);
703 /* ldw -148(sp),rp */
704 while (--i > INITIAL_NSCRATCHREGS) {
705 *instp++ = LDW_NEG(j, REG_SP, scratchregs[i]); /* ldw -124(sp),r4 &c */
706 j += sizeof (int);
707 }
708 *instp++ = BV(0, REG_RTN); /* bv (rp) */
709 *instp++ = LDWM_NEG(FRAME_SIZE, REG_SP, scratchregs[i]);
710 /* ldwm -128(sp),r3
711 in delay slot */
712#endif
713
714 assert(instp - instructions == len);
715 return len;
716}
717
718void
719net_filter_free(filter_fct_t fp, unsigned int len)
720{
721 kfree((vm_offset_t) fp, len);
722}
723
724#else /* NET_FILTER_COMPILER */
725
726/*
727 * Compilation of a source network filter into ppc instructions
728 * - a small version that doesnt do anything, but doesn't take
729 * up any space either. Note that if using a single mklinux server
730 * with ethertalk enabled (standard situation), the filter passes
731 * everything through so no need to compile one. If running multi
732 * servers then there is more of a need. Ethertalk (in linux server)
733 * should really have a packet filter, but at time of writing
734 * it does not.
735 */
736filter_fct_t
737net_filter_alloc(
738 filter_t *fpstart,
739 unsigned int fplen,
740 unsigned int *len)
741{
742 *len = 0;
743 return ((filter_fct_t)0);
744}
745
746void
747net_filter_free(
748 filter_fct_t fp,
749 unsigned int len)
750{
751 assert(fp == (filter_fct_t)0 && len == 0);
752}
753#endif /* NET_FILTER_COMPILER */