• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * bpf_jit_asm64.S: Packet/header access helper functions
3 * for PPC64 BPF compiler.
4 *
5 * Copyright 2016, Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
6 * 		   IBM Corporation
7 *
8 * Based on bpf_jit_asm.S by Matt Evans
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; version 2
13 * of the License.
14 */
15
16#include <asm/ppc_asm.h>
17#include <asm/ptrace.h>
18#include "bpf_jit64.h"
19
20/*
21 * All of these routines are called directly from generated code,
22 * with the below register usage:
23 * r27		skb pointer (ctx)
24 * r25		skb header length
25 * r26		skb->data pointer
26 * r4		offset
27 *
28 * Result is passed back in:
29 * r8		data read in host endian format (accumulator)
30 *
31 * r9 is used as a temporary register
32 */
33
34#define r_skb	r27
35#define r_hlen	r25
36#define r_data	r26
37#define r_off	r4
38#define r_val	r8
39#define r_tmp	r9
40
41_GLOBAL_TOC(sk_load_word)
42	cmpdi	r_off, 0
43	blt	bpf_slow_path_word_neg
44	b	sk_load_word_positive_offset
45
46_GLOBAL_TOC(sk_load_word_positive_offset)
47	/* Are we accessing past headlen? */
48	subi	r_tmp, r_hlen, 4
49	cmpd	r_tmp, r_off
50	blt	bpf_slow_path_word
51	/* Nope, just hitting the header.  cr0 here is eq or gt! */
52	LWZX_BE	r_val, r_data, r_off
53	blr	/* Return success, cr0 != LT */
54
55_GLOBAL_TOC(sk_load_half)
56	cmpdi	r_off, 0
57	blt	bpf_slow_path_half_neg
58	b	sk_load_half_positive_offset
59
60_GLOBAL_TOC(sk_load_half_positive_offset)
61	subi	r_tmp, r_hlen, 2
62	cmpd	r_tmp, r_off
63	blt	bpf_slow_path_half
64	LHZX_BE	r_val, r_data, r_off
65	blr
66
67_GLOBAL_TOC(sk_load_byte)
68	cmpdi	r_off, 0
69	blt	bpf_slow_path_byte_neg
70	b	sk_load_byte_positive_offset
71
72_GLOBAL_TOC(sk_load_byte_positive_offset)
73	cmpd	r_hlen, r_off
74	ble	bpf_slow_path_byte
75	lbzx	r_val, r_data, r_off
76	blr
77
78/*
79 * Call out to skb_copy_bits:
80 * Allocate a new stack frame here to remain ABI-compliant in
81 * stashing LR.
82 */
83#define bpf_slow_path_common(SIZE)					\
84	mflr	r0;							\
85	std	r0, PPC_LR_STKOFF(r1);					\
86	stdu	r1, -(STACK_FRAME_MIN_SIZE + BPF_PPC_STACK_LOCALS)(r1);	\
87	mr	r3, r_skb;						\
88	/* r4 = r_off as passed */					\
89	addi	r5, r1, STACK_FRAME_MIN_SIZE;				\
90	li	r6, SIZE;						\
91	bl	skb_copy_bits;						\
92	nop;								\
93	/* save r5 */							\
94	addi	r5, r1, STACK_FRAME_MIN_SIZE;				\
95	/* r3 = 0 on success */						\
96	addi	r1, r1, STACK_FRAME_MIN_SIZE + BPF_PPC_STACK_LOCALS;	\
97	ld	r0, PPC_LR_STKOFF(r1);					\
98	mtlr	r0;							\
99	cmpdi	r3, 0;							\
100	blt	bpf_error;	/* cr0 = LT */
101
102bpf_slow_path_word:
103	bpf_slow_path_common(4)
104	/* Data value is on stack, and cr0 != LT */
105	LWZX_BE	r_val, 0, r5
106	blr
107
108bpf_slow_path_half:
109	bpf_slow_path_common(2)
110	LHZX_BE	r_val, 0, r5
111	blr
112
113bpf_slow_path_byte:
114	bpf_slow_path_common(1)
115	lbzx	r_val, 0, r5
116	blr
117
118/*
119 * Call out to bpf_internal_load_pointer_neg_helper
120 */
121#define sk_negative_common(SIZE)				\
122	mflr	r0;						\
123	std	r0, PPC_LR_STKOFF(r1);				\
124	stdu	r1, -STACK_FRAME_MIN_SIZE(r1);			\
125	mr	r3, r_skb;					\
126	/* r4 = r_off, as passed */				\
127	li	r5, SIZE;					\
128	bl	bpf_internal_load_pointer_neg_helper;		\
129	nop;							\
130	addi	r1, r1, STACK_FRAME_MIN_SIZE;			\
131	ld	r0, PPC_LR_STKOFF(r1);				\
132	mtlr	r0;						\
133	/* R3 != 0 on success */				\
134	cmpldi	r3, 0;						\
135	beq	bpf_error_slow;	/* cr0 = EQ */
136
137bpf_slow_path_word_neg:
138	lis     r_tmp, -32	/* SKF_LL_OFF */
139	cmpd	r_off, r_tmp	/* addr < SKF_* */
140	blt	bpf_error	/* cr0 = LT */
141	b	sk_load_word_negative_offset
142
143_GLOBAL_TOC(sk_load_word_negative_offset)
144	sk_negative_common(4)
145	LWZX_BE	r_val, 0, r3
146	blr
147
148bpf_slow_path_half_neg:
149	lis     r_tmp, -32	/* SKF_LL_OFF */
150	cmpd	r_off, r_tmp	/* addr < SKF_* */
151	blt	bpf_error	/* cr0 = LT */
152	b	sk_load_half_negative_offset
153
154_GLOBAL_TOC(sk_load_half_negative_offset)
155	sk_negative_common(2)
156	LHZX_BE	r_val, 0, r3
157	blr
158
159bpf_slow_path_byte_neg:
160	lis     r_tmp, -32	/* SKF_LL_OFF */
161	cmpd	r_off, r_tmp	/* addr < SKF_* */
162	blt	bpf_error	/* cr0 = LT */
163	b	sk_load_byte_negative_offset
164
165_GLOBAL_TOC(sk_load_byte_negative_offset)
166	sk_negative_common(1)
167	lbzx	r_val, 0, r3
168	blr
169
170bpf_error_slow:
171	/* fabricate a cr0 = lt */
172	li	r_tmp, -1
173	cmpdi	r_tmp, 0
174bpf_error:
175	/*
176	 * Entered with cr0 = lt
177	 * Generated code will 'blt epilogue', returning 0.
178	 */
179	li	r_val, 0
180	blr
181